• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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