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 "JankTracker.h"
18
19 #include <android/gui/IJankListener.h>
20 #include "BackgroundExecutor.h"
21
22 namespace android {
23
24 namespace {
25
26 constexpr size_t kJankDataBatchSize = 50;
27
28 } // anonymous namespace
29
30 std::atomic<size_t> JankTracker::sListenerCount(0);
31 std::atomic<bool> JankTracker::sCollectAllJankDataForTesting(false);
32
~JankTracker()33 JankTracker::~JankTracker() {}
34
addJankListener(int32_t layerId,sp<IBinder> listener)35 void JankTracker::addJankListener(int32_t layerId, sp<IBinder> listener) {
36 // Increment right away, so that if an onJankData call comes in before the background thread has
37 // added this listener, it will not drop the data.
38 sListenerCount++;
39
40 BackgroundExecutor::getLowPriorityInstance().sendCallbacks(
41 {[layerId, listener = std::move(listener)]() {
42 JankTracker& tracker = getInstance();
43 const std::lock_guard<std::mutex> _l(tracker.mLock);
44 tracker.addJankListenerLocked(layerId, listener);
45 }});
46 }
47
flushJankData(int32_t layerId)48 void JankTracker::flushJankData(int32_t layerId) {
49 BackgroundExecutor::getLowPriorityInstance().sendCallbacks(
50 {[layerId]() { getInstance().doFlushJankData(layerId); }});
51 }
52
removeJankListener(int32_t layerId,sp<IBinder> listener,int64_t afterVsync)53 void JankTracker::removeJankListener(int32_t layerId, sp<IBinder> listener, int64_t afterVsync) {
54 BackgroundExecutor::getLowPriorityInstance().sendCallbacks(
55 {[layerId, listener = std::move(listener), afterVsync]() {
56 JankTracker& tracker = getInstance();
57 const std::lock_guard<std::mutex> _l(tracker.mLock);
58 tracker.markJankListenerForRemovalLocked(layerId, listener, afterVsync);
59 }});
60 }
61
onJankData(int32_t layerId,gui::JankData data)62 void JankTracker::onJankData(int32_t layerId, gui::JankData data) {
63 if (sListenerCount == 0) {
64 return;
65 }
66
67 BackgroundExecutor::getLowPriorityInstance().sendCallbacks(
68 {[layerId, data = std::move(data)]() {
69 JankTracker& tracker = getInstance();
70
71 tracker.mLock.lock();
72 bool hasListeners = tracker.mJankListeners.count(layerId) > 0;
73 tracker.mLock.unlock();
74
75 if (!hasListeners && !sCollectAllJankDataForTesting) {
76 return;
77 }
78
79 tracker.mJankDataLock.lock();
80 tracker.mJankData.emplace(layerId, data);
81 size_t count = tracker.mJankData.count(layerId);
82 tracker.mJankDataLock.unlock();
83
84 if (count >= kJankDataBatchSize && !sCollectAllJankDataForTesting) {
85 tracker.doFlushJankData(layerId);
86 }
87 }});
88 }
89
addJankListenerLocked(int32_t layerId,sp<IBinder> listener)90 void JankTracker::addJankListenerLocked(int32_t layerId, sp<IBinder> listener) {
91 auto range = mJankListeners.equal_range(layerId);
92 for (auto it = range.first; it != range.second; it++) {
93 if (it->second.mListener == listener) {
94 // Undo the duplicate increment in addJankListener.
95 sListenerCount--;
96 return;
97 }
98 }
99
100 mJankListeners.emplace(layerId, std::move(listener));
101 }
102
doFlushJankData(int32_t layerId)103 void JankTracker::doFlushJankData(int32_t layerId) {
104 std::vector<gui::JankData> jankData;
105 int64_t maxVsync = transferAvailableJankData(layerId, jankData);
106
107 std::vector<sp<IBinder>> toSend;
108
109 mLock.lock();
110 auto range = mJankListeners.equal_range(layerId);
111 for (auto it = range.first; it != range.second;) {
112 if (!jankData.empty()) {
113 toSend.emplace_back(it->second.mListener);
114 }
115
116 int64_t removeAfter = it->second.mRemoveAfter;
117 if (removeAfter != -1 && removeAfter <= maxVsync) {
118 it = mJankListeners.erase(it);
119 sListenerCount--;
120 } else {
121 it++;
122 }
123 }
124 mLock.unlock();
125
126 for (const auto& listener : toSend) {
127 binder::Status status = interface_cast<gui::IJankListener>(listener)->onJankData(jankData);
128 if (status.exceptionCode() == binder::Status::EX_NULL_POINTER) {
129 // Remove any listeners, where the App side has gone away, without
130 // deregistering.
131 dropJankListener(layerId, listener);
132 }
133 }
134 }
135
markJankListenerForRemovalLocked(int32_t layerId,sp<IBinder> listener,int64_t afterVysnc)136 void JankTracker::markJankListenerForRemovalLocked(int32_t layerId, sp<IBinder> listener,
137 int64_t afterVysnc) {
138 auto range = mJankListeners.equal_range(layerId);
139 for (auto it = range.first; it != range.second; it++) {
140 if (it->second.mListener == listener) {
141 it->second.mRemoveAfter = std::max(static_cast<int64_t>(0), afterVysnc);
142 return;
143 }
144 }
145 }
146
transferAvailableJankData(int32_t layerId,std::vector<gui::JankData> & outJankData)147 int64_t JankTracker::transferAvailableJankData(int32_t layerId,
148 std::vector<gui::JankData>& outJankData) {
149 const std::lock_guard<std::mutex> _l(mJankDataLock);
150 int64_t maxVsync = 0;
151 auto range = mJankData.equal_range(layerId);
152 for (auto it = range.first; it != range.second;) {
153 maxVsync = std::max(it->second.frameVsyncId, maxVsync);
154 outJankData.emplace_back(std::move(it->second));
155 it = mJankData.erase(it);
156 }
157 return maxVsync;
158 }
159
dropJankListener(int32_t layerId,sp<IBinder> listener)160 void JankTracker::dropJankListener(int32_t layerId, sp<IBinder> listener) {
161 const std::lock_guard<std::mutex> _l(mLock);
162 auto range = mJankListeners.equal_range(layerId);
163 for (auto it = range.first; it != range.second; it++) {
164 if (it->second.mListener == listener) {
165 mJankListeners.erase(it);
166 sListenerCount--;
167 return;
168 }
169 }
170 }
171
clearAndStartCollectingAllJankDataForTesting()172 void JankTracker::clearAndStartCollectingAllJankDataForTesting() {
173 BackgroundExecutor::getLowPriorityInstance().flushQueue();
174
175 // Clear all past tracked jank data.
176 JankTracker& tracker = getInstance();
177 const std::lock_guard<std::mutex> _l(tracker.mJankDataLock);
178 tracker.mJankData.clear();
179
180 // Pretend there's at least one listener.
181 sListenerCount++;
182 sCollectAllJankDataForTesting = true;
183 }
184
getCollectedJankDataForTesting(int32_t layerId)185 std::vector<gui::JankData> JankTracker::getCollectedJankDataForTesting(int32_t layerId) {
186 JankTracker& tracker = getInstance();
187 const std::lock_guard<std::mutex> _l(tracker.mJankDataLock);
188
189 auto range = tracker.mJankData.equal_range(layerId);
190 std::vector<gui::JankData> result;
191 std::transform(range.first, range.second, std::back_inserter(result),
192 [](std::pair<int32_t, gui::JankData> layerIdToJankData) {
193 return layerIdToJankData.second;
194 });
195
196 return result;
197 }
198
clearAndStopCollectingAllJankDataForTesting()199 void JankTracker::clearAndStopCollectingAllJankDataForTesting() {
200 // Undo startCollectingAllJankDataForTesting.
201 sListenerCount--;
202 sCollectAllJankDataForTesting = false;
203
204 // Clear all tracked jank data.
205 JankTracker& tracker = getInstance();
206 const std::lock_guard<std::mutex> _l(tracker.mJankDataLock);
207 tracker.mJankData.clear();
208 }
209
210 } // namespace android
211