blob: e7e1937235a716b2713304e4014de7947434356d [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
19#include <binder/Binder.h>
20#include <gtest/gtest.h>
21#include <inttypes.h>
22#include <log/log.h>
23
24#define TAG "LatencyTracker_test"
25
26using android::inputdispatcher::InputEventTimeline;
27using android::inputdispatcher::LatencyTracker;
28
29namespace android::inputdispatcher {
30
31InputEventTimeline getTestTimeline() {
32 InputEventTimeline t(
33 /*isDown*/ true,
34 /*eventTime*/ 2,
35 /*readTime*/ 3);
36 ConnectionTimeline expectedCT(/*deliveryTime*/ 6, /* consumeTime*/ 7, /*finishTime*/ 8);
37 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
38 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
39 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 10;
40 expectedCT.setGraphicsTimeline(std::move(graphicsTimeline));
41 t.connectionTimelines.emplace(new BBinder(), std::move(expectedCT));
42 return t;
43}
44
45// --- LatencyTrackerTest ---
46class LatencyTrackerTest : public testing::Test, public InputEventTimelineProcessor {
47protected:
48 std::unique_ptr<LatencyTracker> mTracker;
49 sp<IBinder> connection1;
50 sp<IBinder> connection2;
51
52 void SetUp() override {
53 connection1 = new BBinder();
54 connection2 = new BBinder();
55
56 mTracker = std::make_unique<LatencyTracker>(this);
57 }
58 void TearDown() override {}
59
60 void assertReceivedTimeline(const InputEventTimeline& timeline);
61 /**
62 * Timelines can be received in any order (order is not guaranteed). So if we are expecting more
63 * than 1 timeline, use this function to check that the set of received timelines matches
64 * what we expected.
65 */
66 void assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines);
67
68private:
69 void processTimeline(const InputEventTimeline& timeline) override {
70 mReceivedTimelines.push_back(timeline);
71 }
72 std::deque<InputEventTimeline> mReceivedTimelines;
73};
74
75void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
76 mTracker->reportNow();
77 ASSERT_FALSE(mReceivedTimelines.empty());
78 const InputEventTimeline& t = mReceivedTimelines.front();
79 ASSERT_EQ(timeline, t);
80 mReceivedTimelines.pop_front();
81}
82
83/**
84 * We are essentially comparing two multisets, but without constructing them.
85 * This comparison is inefficient, but it avoids having to construct a set, and also avoids the
86 * declaration of copy constructor for ConnectionTimeline.
87 * We ensure that collections A and B have the same size, that for every element in A, there is an
88 * equal element in B, and for every element in B there is an equal element in A.
89 */
90void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
91 mTracker->reportNow();
92 ASSERT_EQ(timelines.size(), mReceivedTimelines.size());
93 for (const InputEventTimeline& expectedTimeline : timelines) {
94 bool found = false;
95 for (const InputEventTimeline& receivedTimeline : mReceivedTimelines) {
96 if (receivedTimeline == expectedTimeline) {
97 found = true;
98 break;
99 }
100 }
101 ASSERT_TRUE(found) << "Could not find expected timeline with eventTime="
102 << expectedTimeline.eventTime;
103 }
104 for (const InputEventTimeline& receivedTimeline : mReceivedTimelines) {
105 bool found = false;
106 for (const InputEventTimeline& expectedTimeline : timelines) {
107 if (receivedTimeline == expectedTimeline) {
108 found = true;
109 break;
110 }
111 }
112 ASSERT_TRUE(found) << "Could not find received timeline with eventTime="
113 << receivedTimeline.eventTime;
114 }
115 mReceivedTimelines.clear();
116}
117
118/**
119 * Ensure that calling 'trackListener' in isolation only creates an inputflinger timeline, without
120 * any additional ConnectionTimeline's.
121 */
122TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
123 mTracker->trackListener(1 /*inputEventId*/, false /*isDown*/, 2 /*eventTime*/, 3 /*readTime*/);
124 assertReceivedTimeline(InputEventTimeline{false, 2, 3});
125}
126
127/**
128 * A single call to trackFinishedEvent should not cause a timeline to be reported.
129 */
130TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
131 mTracker->trackFinishedEvent(1 /*inputEventId*/, connection1, 2 /*deliveryTime*/,
132 3 /*consumeTime*/, 4 /*finishTime*/);
133 assertReceivedTimelines({});
134}
135
136/**
137 * A single call to trackGraphicsLatency should not cause a timeline to be reported.
138 */
139TEST_F(LatencyTrackerTest, TrackGraphicsLatency_DoesNotTriggerReporting) {
140 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
141 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
142 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
143 mTracker->trackGraphicsLatency(1 /*inputEventId*/, connection2, graphicsTimeline);
144 assertReceivedTimelines({});
145}
146
147TEST_F(LatencyTrackerTest, TrackAllParameters_ReportsFullTimeline) {
148 constexpr int32_t inputEventId = 1;
149 InputEventTimeline expected = getTestTimeline();
150
151 const auto& [connectionToken, expectedCT] = *expected.connectionTimelines.begin();
152
153 mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
154 mTracker->trackFinishedEvent(inputEventId, connectionToken, expectedCT.deliveryTime,
155 expectedCT.consumeTime, expectedCT.finishTime);
156 mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
157
158 assertReceivedTimeline(expected);
159}
160
161TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
162 constexpr int32_t inputEventId1 = 1;
163 InputEventTimeline timeline1(
164 /*isDown*/ true,
165 /*eventTime*/ 2,
166 /*readTime*/ 3);
167 timeline1.connectionTimelines.emplace(connection1,
168 ConnectionTimeline(/*deliveryTime*/ 6, /*consumeTime*/ 7,
169 /*finishTime*/ 8));
170 ConnectionTimeline& connectionTimeline1 = timeline1.connectionTimelines.begin()->second;
171 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline1;
172 graphicsTimeline1[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
173 graphicsTimeline1[GraphicsTimeline::PRESENT_TIME] = 10;
174 connectionTimeline1.setGraphicsTimeline(std::move(graphicsTimeline1));
175
176 constexpr int32_t inputEventId2 = 10;
177 InputEventTimeline timeline2(
178 /*isDown*/ false,
179 /*eventTime*/ 20,
180 /*readTime*/ 30);
181 timeline2.connectionTimelines.emplace(connection2,
182 ConnectionTimeline(/*deliveryTime*/ 60,
183 /*consumeTime*/ 70,
184 /*finishTime*/ 80));
185 ConnectionTimeline& connectionTimeline2 = timeline2.connectionTimelines.begin()->second;
186 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline2;
187 graphicsTimeline2[GraphicsTimeline::GPU_COMPLETED_TIME] = 90;
188 graphicsTimeline2[GraphicsTimeline::PRESENT_TIME] = 100;
189 connectionTimeline2.setGraphicsTimeline(std::move(graphicsTimeline2));
190
191 // Start processing first event
192 mTracker->trackListener(inputEventId1, timeline1.isDown, timeline1.eventTime,
193 timeline1.readTime);
194 // Start processing second event
195 mTracker->trackListener(inputEventId2, timeline2.isDown, timeline2.eventTime,
196 timeline2.readTime);
197 mTracker->trackFinishedEvent(inputEventId1, connection1, connectionTimeline1.deliveryTime,
198 connectionTimeline1.consumeTime, connectionTimeline1.finishTime);
199
200 mTracker->trackFinishedEvent(inputEventId2, connection2, connectionTimeline2.deliveryTime,
201 connectionTimeline2.consumeTime, connectionTimeline2.finishTime);
202 mTracker->trackGraphicsLatency(inputEventId1, connection1,
203 connectionTimeline1.graphicsTimeline);
204 mTracker->trackGraphicsLatency(inputEventId2, connection2,
205 connectionTimeline2.graphicsTimeline);
206 // Now both events should be completed
207 assertReceivedTimelines({timeline1, timeline2});
208}
209
210/**
211 * Check that LatencyTracker consistently tracks events even if there are many incomplete events.
212 */
213TEST_F(LatencyTrackerTest, IncompleteEvents_AreHandledConsistently) {
214 InputEventTimeline timeline = getTestTimeline();
215 std::vector<InputEventTimeline> expectedTimelines;
216 const ConnectionTimeline& expectedCT = timeline.connectionTimelines.begin()->second;
217 const sp<IBinder>& token = timeline.connectionTimelines.begin()->first;
218
219 for (size_t i = 1; i <= 100; i++) {
220 mTracker->trackListener(i /*inputEventId*/, timeline.isDown, timeline.eventTime,
221 timeline.readTime);
222 expectedTimelines.push_back(
223 InputEventTimeline{timeline.isDown, timeline.eventTime, timeline.readTime});
224 }
225 // Now, complete the first event that was sent.
226 mTracker->trackFinishedEvent(1 /*inputEventId*/, token, expectedCT.deliveryTime,
227 expectedCT.consumeTime, expectedCT.finishTime);
228 mTracker->trackGraphicsLatency(1 /*inputEventId*/, token, expectedCT.graphicsTimeline);
229
230 expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
231 assertReceivedTimelines(expectedTimelines);
232}
233
234/**
235 * For simplicity of the implementation, LatencyTracker only starts tracking an event when
236 * 'trackListener' is invoked.
237 * Both 'trackFinishedEvent' and 'trackGraphicsLatency' should not start a new event.
238 * If they are received before 'trackListener' (which should not be possible), they are ignored.
239 */
240TEST_F(LatencyTrackerTest, EventsAreTracked_WhenTrackListenerIsCalledFirst) {
241 constexpr int32_t inputEventId = 1;
242 InputEventTimeline expected = getTestTimeline();
243 const ConnectionTimeline& expectedCT = expected.connectionTimelines.begin()->second;
244 mTracker->trackFinishedEvent(inputEventId, connection1, expectedCT.deliveryTime,
245 expectedCT.consumeTime, expectedCT.finishTime);
246 mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
247
248 mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
249 assertReceivedTimeline(
250 InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
251}
252
253} // namespace android::inputdispatcher