xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Jank/JankTracker.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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