1 /*
2 * Copyright 2024 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 <android/gui/BnJankListener.h>
18 #include <binder/IInterface.h>
19 #include "BackgroundExecutor.h"
20 #include "Jank/JankTracker.h"
21
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24
25 namespace android {
26
27 namespace {
28
29 using namespace testing;
30
31 class MockJankListener : public gui::BnJankListener {
32 public:
33 MockJankListener() = default;
34 ~MockJankListener() override = default;
35
36 MOCK_METHOD(binder::Status, onJankData, (const std::vector<gui::JankData>& jankData),
37 (override));
38 };
39
40 } // anonymous namespace
41
42 class JankTrackerTest : public Test {
43 public:
JankTrackerTest()44 JankTrackerTest() {}
45
SetUp()46 void SetUp() override { mListener = sp<StrictMock<MockJankListener>>::make(); }
47
addJankListener(int32_t layerId)48 void addJankListener(int32_t layerId) {
49 JankTracker::addJankListener(layerId, IInterface::asBinder(mListener));
50 }
51
removeJankListener(int32_t layerId,int64_t after)52 void removeJankListener(int32_t layerId, int64_t after) {
53 JankTracker::removeJankListener(layerId, IInterface::asBinder(mListener), after);
54 }
55
addJankData(int32_t layerId,int jankType)56 void addJankData(int32_t layerId, int jankType) {
57 gui::JankData data;
58 data.frameVsyncId = mVsyncId++;
59 data.jankType = jankType;
60 data.frameIntervalNs = 8333333;
61 JankTracker::onJankData(layerId, data);
62 }
63
flushBackgroundThread()64 void flushBackgroundThread() { BackgroundExecutor::getLowPriorityInstance().flushQueue(); }
65
listenerCount()66 size_t listenerCount() { return JankTracker::sListenerCount; }
67
getCollectedJankData(int32_t layerId)68 std::vector<gui::JankData> getCollectedJankData(int32_t layerId) {
69 return JankTracker::getCollectedJankDataForTesting(layerId);
70 }
71
72 sp<StrictMock<MockJankListener>> mListener = nullptr;
73 int64_t mVsyncId = 1000;
74 };
75
TEST_F(JankTrackerTest,jankDataIsTrackedAndPropagated)76 TEST_F(JankTrackerTest, jankDataIsTrackedAndPropagated) {
77 ASSERT_EQ(listenerCount(), 0u);
78
79 EXPECT_CALL(*mListener.get(), onJankData(SizeIs(3)))
80 .WillOnce([](const std::vector<gui::JankData>& jankData) {
81 EXPECT_EQ(jankData[0].frameVsyncId, 1000);
82 EXPECT_EQ(jankData[0].jankType, 1);
83 EXPECT_EQ(jankData[0].frameIntervalNs, 8333333);
84
85 EXPECT_EQ(jankData[1].frameVsyncId, 1001);
86 EXPECT_EQ(jankData[1].jankType, 2);
87 EXPECT_EQ(jankData[1].frameIntervalNs, 8333333);
88
89 EXPECT_EQ(jankData[2].frameVsyncId, 1002);
90 EXPECT_EQ(jankData[2].jankType, 3);
91 EXPECT_EQ(jankData[2].frameIntervalNs, 8333333);
92 return binder::Status::ok();
93 });
94 EXPECT_CALL(*mListener.get(), onJankData(SizeIs(2)))
95 .WillOnce([](const std::vector<gui::JankData>& jankData) {
96 EXPECT_EQ(jankData[0].frameVsyncId, 1003);
97 EXPECT_EQ(jankData[0].jankType, 4);
98 EXPECT_EQ(jankData[0].frameIntervalNs, 8333333);
99
100 EXPECT_EQ(jankData[1].frameVsyncId, 1004);
101 EXPECT_EQ(jankData[1].jankType, 5);
102 EXPECT_EQ(jankData[1].frameIntervalNs, 8333333);
103
104 return binder::Status::ok();
105 });
106
107 addJankListener(123);
108 addJankData(123, 1);
109 addJankData(123, 2);
110 addJankData(123, 3);
111 JankTracker::flushJankData(123);
112 addJankData(123, 4);
113 removeJankListener(123, mVsyncId);
114 addJankData(123, 5);
115 JankTracker::flushJankData(123);
116 addJankData(123, 6);
117 JankTracker::flushJankData(123);
118 removeJankListener(123, 0);
119
120 flushBackgroundThread();
121 }
122
TEST_F(JankTrackerTest,jankDataIsAutomaticallyFlushedInBatches)123 TEST_F(JankTrackerTest, jankDataIsAutomaticallyFlushedInBatches) {
124 ASSERT_EQ(listenerCount(), 0u);
125
126 // needs to be larger than kJankDataBatchSize in JankTracker.cpp.
127 constexpr size_t kNumberOfJankDataToSend = 234;
128
129 size_t jankDataReceived = 0;
130 size_t numBatchesReceived = 0;
131
132 EXPECT_CALL(*mListener.get(), onJankData(_))
133 .WillRepeatedly([&](const std::vector<gui::JankData>& jankData) {
134 jankDataReceived += jankData.size();
135 numBatchesReceived++;
136 return binder::Status::ok();
137 });
138
139 addJankListener(123);
140 for (size_t i = 0; i < kNumberOfJankDataToSend; i++) {
141 addJankData(123, 0);
142 }
143
144 flushBackgroundThread();
145 // Check that we got some data, without explicitly flushing.
146 EXPECT_GT(jankDataReceived, 0u);
147 EXPECT_GT(numBatchesReceived, 0u);
148 EXPECT_LT(numBatchesReceived, jankDataReceived); // batches should be > size 1.
149
150 removeJankListener(123, 0);
151 JankTracker::flushJankData(123);
152 flushBackgroundThread();
153 EXPECT_EQ(jankDataReceived, kNumberOfJankDataToSend);
154 }
155
TEST_F(JankTrackerTest,jankListenerIsRemovedWhenReturningNullError)156 TEST_F(JankTrackerTest, jankListenerIsRemovedWhenReturningNullError) {
157 ASSERT_EQ(listenerCount(), 0u);
158
159 EXPECT_CALL(*mListener.get(), onJankData(SizeIs(3)))
160 .WillOnce(Return(binder::Status::fromExceptionCode(binder::Status::EX_NULL_POINTER)));
161
162 addJankListener(123);
163 addJankData(123, 1);
164 addJankData(123, 2);
165 addJankData(123, 3);
166 JankTracker::flushJankData(123);
167 addJankData(123, 4);
168 addJankData(123, 5);
169 JankTracker::flushJankData(123);
170 flushBackgroundThread();
171
172 EXPECT_EQ(listenerCount(), 0u);
173 }
174
TEST_F(JankTrackerTest,jankDataIsDroppedIfNobodyIsListening)175 TEST_F(JankTrackerTest, jankDataIsDroppedIfNobodyIsListening) {
176 ASSERT_EQ(listenerCount(), 0u);
177
178 addJankData(123, 1);
179 addJankData(123, 2);
180 addJankData(123, 3);
181 flushBackgroundThread();
182
183 EXPECT_EQ(getCollectedJankData(123).size(), 0u);
184 }
185
TEST_F(JankTrackerTest,listenerCountTracksRegistrations)186 TEST_F(JankTrackerTest, listenerCountTracksRegistrations) {
187 ASSERT_EQ(listenerCount(), 0u);
188
189 addJankListener(123);
190 addJankListener(456);
191 flushBackgroundThread();
192 EXPECT_EQ(listenerCount(), 2u);
193
194 removeJankListener(123, 0);
195 JankTracker::flushJankData(123);
196 removeJankListener(456, 0);
197 JankTracker::flushJankData(456);
198 flushBackgroundThread();
199 EXPECT_EQ(listenerCount(), 0u);
200 }
201
TEST_F(JankTrackerTest,listenerCountIsAccurateOnDuplicateRegistration)202 TEST_F(JankTrackerTest, listenerCountIsAccurateOnDuplicateRegistration) {
203 ASSERT_EQ(listenerCount(), 0u);
204
205 addJankListener(123);
206 addJankListener(123);
207 flushBackgroundThread();
208 EXPECT_EQ(listenerCount(), 1u);
209
210 removeJankListener(123, 0);
211 JankTracker::flushJankData(123);
212 flushBackgroundThread();
213 EXPECT_EQ(listenerCount(), 0u);
214 }
215
TEST_F(JankTrackerTest,multipleLayersAreTrackedIndependently)216 TEST_F(JankTrackerTest, multipleLayersAreTrackedIndependently) {
217 size_t jankDataReceived = 0;
218 size_t numBatchesReceived = 0;
219
220 EXPECT_CALL(*mListener.get(), onJankData(_))
221 .WillRepeatedly([&](const std::vector<gui::JankData>& jankData) {
222 jankDataReceived += jankData.size();
223 numBatchesReceived++;
224 return binder::Status::ok();
225 });
226 addJankListener(123);
227 addJankListener(321);
228 addJankData(123, 1);
229 addJankData(123, 2);
230 addJankData(123, 3);
231 addJankData(321, 4);
232 addJankData(321, 5);
233
234 JankTracker::flushJankData(123);
235 flushBackgroundThread();
236 EXPECT_EQ(numBatchesReceived, 1u);
237 EXPECT_EQ(jankDataReceived, 3u);
238
239 JankTracker::flushJankData(321);
240 flushBackgroundThread();
241 EXPECT_EQ(numBatchesReceived, 2u);
242 EXPECT_EQ(jankDataReceived, 5u);
243 }
244
245 } // namespace android
246