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 <binder/Binder.h>
20 #include <gtest/gtest.h>
21 #include <inttypes.h>
22 #include <log/log.h>
23 
24 #define TAG "LatencyTracker_test"
25 
26 using android::inputdispatcher::InputEventTimeline;
27 using android::inputdispatcher::LatencyTracker;
28 
29 namespace android::inputdispatcher {
30 
getTestTimeline()31 InputEventTimeline 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 ---
46 class LatencyTrackerTest : public testing::Test, public InputEventTimelineProcessor {
47 protected:
48     std::unique_ptr<LatencyTracker> mTracker;
49     sp<IBinder> connection1;
50     sp<IBinder> connection2;
51 
SetUp()52     void SetUp() override {
53         connection1 = new BBinder();
54         connection2 = new BBinder();
55 
56         mTracker = std::make_unique<LatencyTracker>(this);
57     }
TearDown()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 
68 private:
processTimeline(const InputEventTimeline & timeline)69     void processTimeline(const InputEventTimeline& timeline) override {
70         mReceivedTimelines.push_back(timeline);
71     }
72     std::deque<InputEventTimeline> mReceivedTimelines;
73 };
74 
assertReceivedTimeline(const InputEventTimeline & timeline)75 void 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  */
assertReceivedTimelines(const std::vector<InputEventTimeline> & timelines)90 void 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  */
TEST_F(LatencyTrackerTest,TrackListener_DoesNotTriggerReporting)122 TEST_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  */
TEST_F(LatencyTrackerTest,TrackFinishedEvent_DoesNotTriggerReporting)130 TEST_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  */
TEST_F(LatencyTrackerTest,TrackGraphicsLatency_DoesNotTriggerReporting)139 TEST_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 
TEST_F(LatencyTrackerTest,TrackAllParameters_ReportsFullTimeline)147 TEST_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 
TEST_F(LatencyTrackerTest,MultipleEvents_AreReportedConsistently)161 TEST_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  */
TEST_F(LatencyTrackerTest,IncompleteEvents_AreHandledConsistently)213 TEST_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  */
TEST_F(LatencyTrackerTest,EventsAreTracked_WhenTrackListenerIsCalledFirst)240 TEST_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
254