• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 <android-base/properties.h>
20 #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 
27 using android::base::HwTimeoutMultiplier;
28 using android::inputdispatcher::InputEventTimeline;
29 using android::inputdispatcher::LatencyTracker;
30 
31 namespace android::inputdispatcher {
32 
33 const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
34         android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
35         HwTimeoutMultiplier());
36 
getTestTimeline()37 InputEventTimeline getTestTimeline() {
38     InputEventTimeline t(
39             /*isDown=*/true,
40             /*eventTime=*/2,
41             /*readTime=*/3);
42     ConnectionTimeline expectedCT(/*deliveryTime=*/6, /*consumeTime=*/7, /*finishTime=*/8);
43     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));
47     t.connectionTimelines.emplace(sp<BBinder>::make(), std::move(expectedCT));
48     return t;
49 }
50 
51 // --- LatencyTrackerTest ---
52 class LatencyTrackerTest : public testing::Test, public InputEventTimelineProcessor {
53 protected:
54     std::unique_ptr<LatencyTracker> mTracker;
55     sp<IBinder> connection1;
56     sp<IBinder> connection2;
57 
SetUp()58     void SetUp() override {
59         connection1 = sp<BBinder>::make();
60         connection2 = sp<BBinder>::make();
61 
62         mTracker = std::make_unique<LatencyTracker>(this);
63     }
TearDown()64     void TearDown() override {}
65 
66     void triggerEventReporting(nsecs_t lastEventTime);
67 
68     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 
76 private:
processTimeline(const InputEventTimeline & timeline)77     void processTimeline(const InputEventTimeline& timeline) override {
78         mReceivedTimelines.push_back(timeline);
79     }
80     std::deque<InputEventTimeline> mReceivedTimelines;
81 };
82 
83 /**
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  */
triggerEventReporting(nsecs_t lastEventTime)87 void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
88     const nsecs_t triggerEventTime =
89             lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
90     mTracker->trackListener(/*inputEventId=*/1, /*isDown=*/true, triggerEventTime,
91                             /*readTime=*/3);
92 }
93 
assertReceivedTimeline(const InputEventTimeline & timeline)94 void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
95     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  */
assertReceivedTimelines(const std::vector<InputEventTimeline> & timelines)108 void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
109     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  */
TEST_F(LatencyTrackerTest,TrackListener_DoesNotTriggerReporting)139 TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
140     mTracker->trackListener(/*inputEventId=*/1, /*isDown=*/false, /*eventTime=*/2,
141                             /*readTime=*/3);
142     triggerEventReporting(/*eventTime=*/2);
143     assertReceivedTimeline(InputEventTimeline{false, 2, 3});
144 }
145 
146 /**
147  * A single call to trackFinishedEvent should not cause a timeline to be reported.
148  */
TEST_F(LatencyTrackerTest,TrackFinishedEvent_DoesNotTriggerReporting)149 TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
150     mTracker->trackFinishedEvent(/*inputEventId=*/1, connection1, /*deliveryTime=*/2,
151                                  /*consumeTime=*/3, /*finishTime=*/4);
152     triggerEventReporting(/*eventTime=*/4);
153     assertReceivedTimelines({});
154 }
155 
156 /**
157  * A single call to trackGraphicsLatency should not cause a timeline to be reported.
158  */
TEST_F(LatencyTrackerTest,TrackGraphicsLatency_DoesNotTriggerReporting)159 TEST_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;
163     mTracker->trackGraphicsLatency(/*inputEventId=*/1, connection2, graphicsTimeline);
164     triggerEventReporting(/*eventTime=*/3);
165     assertReceivedTimelines({});
166 }
167 
TEST_F(LatencyTrackerTest,TrackAllParameters_ReportsFullTimeline)168 TEST_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 
179     triggerEventReporting(expected.eventTime);
180     assertReceivedTimeline(expected);
181 }
182 
183 /**
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  */
TEST_F(LatencyTrackerTest,WhenDuplicateEventsAreReported_DoesNotCrash)187 TEST_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.
194     mTracker->trackListener(inputEventId, isDown, /*eventTime=*/1, readTime);
195     mTracker->trackListener(inputEventId, isDown, /*eventTime=*/2, readTime);
196 
197     triggerEventReporting(/*eventTime=*/2);
198     // 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 
TEST_F(LatencyTrackerTest,MultipleEvents_AreReportedConsistently)203 TEST_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(
220             /*isDown=*/false,
221             /*eventTime=*/20,
222             /*readTime=*/30);
223     timeline2.connectionTimelines.emplace(connection2,
224                                           ConnectionTimeline(/*deliveryTime=*/60,
225                                                              /*consumeTime=*/70,
226                                                              /*finishTime=*/80));
227     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
249     triggerEventReporting(timeline2.eventTime);
250     assertReceivedTimelines({timeline1, timeline2});
251 }
252 
253 /**
254  * Check that LatencyTracker consistently tracks events even if there are many incomplete events.
255  */
TEST_F(LatencyTrackerTest,IncompleteEvents_AreHandledConsistently)256 TEST_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++) {
263         mTracker->trackListener(/*inputEventId=*/i, timeline.isDown, timeline.eventTime,
264                                 timeline.readTime);
265         expectedTimelines.push_back(
266                 InputEventTimeline{timeline.isDown, timeline.eventTime, timeline.readTime});
267     }
268     // Now, complete the first event that was sent.
269     mTracker->trackFinishedEvent(/*inputEventId=*/1, token, expectedCT.deliveryTime,
270                                  expectedCT.consumeTime, expectedCT.finishTime);
271     mTracker->trackGraphicsLatency(/*inputEventId=*/1, token, expectedCT.graphicsTimeline);
272 
273     expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
274     triggerEventReporting(timeline.eventTime);
275     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  */
TEST_F(LatencyTrackerTest,EventsAreTracked_WhenTrackListenerIsCalledFirst)284 TEST_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);
293     triggerEventReporting(expected.eventTime);
294     assertReceivedTimeline(
295             InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
296 }
297 
298 } // namespace android::inputdispatcher
299