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 for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
92 if (it->second.mListener == listener) {
93 // Undo the duplicate increment in addJankListener.
94 sListenerCount--;
95 return;
96 }
97 }
98
99 mJankListeners.emplace(layerId, std::move(listener));
100 }
101
doFlushJankData(int32_t layerId)102 void JankTracker::doFlushJankData(int32_t layerId) {
103 std::vector<gui::JankData> jankData;
104 int64_t maxVsync = transferAvailableJankData(layerId, jankData);
105
106 std::vector<sp<IBinder>> toSend;
107
108 mLock.lock();
109 for (auto it = mJankListeners.find(layerId); it != mJankListeners.end();) {
110 if (!jankData.empty()) {
111 toSend.emplace_back(it->second.mListener);
112 }
113
114 int64_t removeAfter = it->second.mRemoveAfter;
115 if (removeAfter != -1 && removeAfter <= maxVsync) {
116 it = mJankListeners.erase(it);
117 sListenerCount--;
118 } else {
119 it++;
120 }
121 }
122 mLock.unlock();
123
124 for (const auto& listener : toSend) {
125 binder::Status status = interface_cast<gui::IJankListener>(listener)->onJankData(jankData);
126 if (status.exceptionCode() == binder::Status::EX_NULL_POINTER) {
127 // Remove any listeners, where the App side has gone away, without
128 // deregistering.
129 dropJankListener(layerId, listener);
130 }
131 }
132 }
133
markJankListenerForRemovalLocked(int32_t layerId,sp<IBinder> listener,int64_t afterVysnc)134 void JankTracker::markJankListenerForRemovalLocked(int32_t layerId, sp<IBinder> listener,
135 int64_t afterVysnc) {
136 for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
137 if (it->second.mListener == listener) {
138 it->second.mRemoveAfter = std::max(static_cast<int64_t>(0), afterVysnc);
139 return;
140 }
141 }
142 }
143
transferAvailableJankData(int32_t layerId,std::vector<gui::JankData> & outJankData)144 int64_t JankTracker::transferAvailableJankData(int32_t layerId,
145 std::vector<gui::JankData>& outJankData) {
146 const std::lock_guard<std::mutex> _l(mJankDataLock);
147 int64_t maxVsync = 0;
148 auto range = mJankData.equal_range(layerId);
149 for (auto it = range.first; it != range.second;) {
150 maxVsync = std::max(it->second.frameVsyncId, maxVsync);
151 outJankData.emplace_back(std::move(it->second));
152 it = mJankData.erase(it);
153 }
154 return maxVsync;
155 }
156
dropJankListener(int32_t layerId,sp<IBinder> listener)157 void JankTracker::dropJankListener(int32_t layerId, sp<IBinder> listener) {
158 const std::lock_guard<std::mutex> _l(mLock);
159 for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
160 if (it->second.mListener == listener) {
161 mJankListeners.erase(it);
162 sListenerCount--;
163 return;
164 }
165 }
166 }
167
clearAndStartCollectingAllJankDataForTesting()168 void JankTracker::clearAndStartCollectingAllJankDataForTesting() {
169 BackgroundExecutor::getLowPriorityInstance().flushQueue();
170
171 // Clear all past tracked jank data.
172 JankTracker& tracker = getInstance();
173 const std::lock_guard<std::mutex> _l(tracker.mJankDataLock);
174 tracker.mJankData.clear();
175
176 // Pretend there's at least one listener.
177 sListenerCount++;
178 sCollectAllJankDataForTesting = true;
179 }
180
getCollectedJankDataForTesting(int32_t layerId)181 std::vector<gui::JankData> JankTracker::getCollectedJankDataForTesting(int32_t layerId) {
182 JankTracker& tracker = getInstance();
183 const std::lock_guard<std::mutex> _l(tracker.mJankDataLock);
184
185 auto range = tracker.mJankData.equal_range(layerId);
186 std::vector<gui::JankData> result;
187 std::transform(range.first, range.second, std::back_inserter(result),
188 [](std::pair<int32_t, gui::JankData> layerIdToJankData) {
189 return layerIdToJankData.second;
190 });
191
192 return result;
193 }
194
clearAndStopCollectingAllJankDataForTesting()195 void JankTracker::clearAndStopCollectingAllJankDataForTesting() {
196 // Undo startCollectingAllJankDataForTesting.
197 sListenerCount--;
198 sCollectAllJankDataForTesting = false;
199
200 // Clear all tracked jank data.
201 JankTracker& tracker = getInstance();
202 const std::lock_guard<std::mutex> _l(tracker.mJankDataLock);
203 tracker.mJankData.clear();
204 }
205
206 } // namespace android
207