blob: 1d2217d322fb59a0800c725f169458896d1e5585 [file] [log] [blame]
Marissa Walle2ffb422018-10-12 11:33:52 -07001/*
2 * Copyright 2018 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//#define LOG_NDEBUG 0
18#undef LOG_TAG
19#define LOG_TAG "TransactionCompletedThread"
20#define ATRACE_TAG ATRACE_TAG_GRAPHICS
21
22#include "TransactionCompletedThread.h"
23
24#include <cinttypes>
25
26#include <binder/IInterface.h>
27#include <gui/ITransactionCompletedListener.h>
28#include <utils/RefBase.h>
29
30namespace android {
31
Marissa Walld600d572019-03-26 15:38:50 -070032// Returns 0 if they are equal
33// <0 if the first id that doesn't match is lower in c2 or all ids match but c2 is shorter
34// >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer
35//
36// See CallbackIdsHash for a explaniation of why this works
37static int compareCallbackIds(const std::vector<CallbackId>& c1, const std::vector<CallbackId> c2) {
38 if (c1.empty()) {
39 return !c2.empty();
40 }
41 return c1.front() - c2.front();
42}
43
Marissa Walle2ffb422018-10-12 11:33:52 -070044TransactionCompletedThread::~TransactionCompletedThread() {
Marissa Wall99343ba2018-11-13 10:39:08 -080045 std::lock_guard lockThread(mThreadMutex);
46
Marissa Walle2ffb422018-10-12 11:33:52 -070047 {
48 std::lock_guard lock(mMutex);
49 mKeepRunning = false;
50 mConditionVariable.notify_all();
51 }
52
Marissa Wall05d9dd32018-11-13 10:05:14 -080053 if (mThread.joinable()) {
54 mThread.join();
55 }
Marissa Walle2ffb422018-10-12 11:33:52 -070056
57 {
58 std::lock_guard lock(mMutex);
Marissa Walld600d572019-03-26 15:38:50 -070059 for (const auto& [listener, transactionStats] : mCompletedTransactions) {
60 IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient);
Marissa Walle2ffb422018-10-12 11:33:52 -070061 }
62 }
63}
64
65void TransactionCompletedThread::run() {
66 std::lock_guard lock(mMutex);
Marissa Wall99343ba2018-11-13 10:39:08 -080067 if (mRunning || !mKeepRunning) {
Marissa Walle2ffb422018-10-12 11:33:52 -070068 return;
69 }
70 mDeathRecipient = new ThreadDeathRecipient();
71 mRunning = true;
Marissa Wall99343ba2018-11-13 10:39:08 -080072
73 std::lock_guard lockThread(mThreadMutex);
Marissa Walle2ffb422018-10-12 11:33:52 -070074 mThread = std::thread(&TransactionCompletedThread::threadMain, this);
75}
76
Marissa Walld600d572019-03-26 15:38:50 -070077status_t TransactionCompletedThread::addCallback(const sp<ITransactionCompletedListener>& listener,
78 const std::vector<CallbackId>& callbackIds) {
Marissa Walle2ffb422018-10-12 11:33:52 -070079 std::lock_guard lock(mMutex);
Marissa Walld600d572019-03-26 15:38:50 -070080 if (!mRunning) {
81 ALOGE("cannot add callback because the callback thread isn't running");
82 return BAD_VALUE;
Marissa Wall3dad52d2019-03-22 14:03:19 -070083 }
84
Marissa Walld600d572019-03-26 15:38:50 -070085 if (mCompletedTransactions.count(listener) == 0) {
86 status_t err = IInterface::asBinder(listener)->linkToDeath(mDeathRecipient);
Marissa Wall3dad52d2019-03-22 14:03:19 -070087 if (err != NO_ERROR) {
88 ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
89 return err;
Marissa Walle2ffb422018-10-12 11:33:52 -070090 }
91 }
92
Marissa Walld600d572019-03-26 15:38:50 -070093 auto& transactionStatsDeque = mCompletedTransactions[listener];
94 transactionStatsDeque.emplace_back(callbackIds);
95 return NO_ERROR;
96}
97
98status_t TransactionCompletedThread::registerPendingCallbackHandle(
99 const sp<CallbackHandle>& handle) {
100 std::lock_guard lock(mMutex);
101 if (!mRunning) {
102 ALOGE("cannot register callback handle because the callback thread isn't running");
103 return BAD_VALUE;
104 }
105
106 // If we can't find the transaction stats something has gone wrong. The client should call
107 // addCallback before trying to register a pending callback handle.
108 TransactionStats* transactionStats;
109 status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
110 if (err != NO_ERROR) {
111 ALOGE("cannot find transaction stats");
112 return err;
113 }
114
115 mPendingTransactions[handle->listener][handle->callbackIds]++;
116 return NO_ERROR;
117}
118
119status_t TransactionCompletedThread::addPresentedCallbackHandles(
120 const std::deque<sp<CallbackHandle>>& handles) {
121 std::lock_guard lock(mMutex);
122 if (!mRunning) {
123 ALOGE("cannot add presented callback handle because the callback thread isn't running");
124 return BAD_VALUE;
125 }
126
127 for (const auto& handle : handles) {
128 auto listener = mPendingTransactions.find(handle->listener);
129 if (listener != mPendingTransactions.end()) {
130 auto& pendingCallbacks = listener->second;
131 auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
132
133 if (pendingCallback != pendingCallbacks.end()) {
134 auto& pendingCount = pendingCallback->second;
135
136 // Decrease the pending count for this listener
137 if (--pendingCount == 0) {
138 pendingCallbacks.erase(pendingCallback);
139 }
140 } else {
141 ALOGW("there are more latched callbacks than there were registered callbacks");
142 }
143 } else {
144 ALOGW("cannot find listener in mPendingTransactions");
145 }
146
147 status_t err = addCallbackHandle(handle);
148 if (err != NO_ERROR) {
149 ALOGE("could not add callback handle");
150 return err;
151 }
152 }
153
154 return NO_ERROR;
155}
156
157status_t TransactionCompletedThread::addUnpresentedCallbackHandle(
158 const sp<CallbackHandle>& handle) {
159 std::lock_guard lock(mMutex);
160 if (!mRunning) {
161 ALOGE("cannot add unpresented callback handle because the callback thread isn't running");
162 return BAD_VALUE;
163 }
164
165 return addCallbackHandle(handle);
166}
167
168status_t TransactionCompletedThread::findTransactionStats(
169 const sp<ITransactionCompletedListener>& listener,
170 const std::vector<CallbackId>& callbackIds, TransactionStats** outTransactionStats) {
171 auto& transactionStatsDeque = mCompletedTransactions[listener];
172
173 // Search back to front because the most recent transactions are at the back of the deque
174 auto itr = transactionStatsDeque.rbegin();
175 for (; itr != transactionStatsDeque.rend(); itr++) {
176 if (compareCallbackIds(itr->callbackIds, callbackIds) == 0) {
177 *outTransactionStats = &(*itr);
178 return NO_ERROR;
179 }
180 }
181
182 ALOGE("could not find transaction stats");
183 return BAD_VALUE;
184}
185
186status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
187 // If we can't find the transaction stats something has gone wrong. The client should call
188 // addCallback before trying to add a presnted callback handle.
189 TransactionStats* transactionStats;
190 status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
191 if (err != NO_ERROR) {
192 return err;
193 }
194
195 transactionStats->latchTime = handle->latchTime;
196 transactionStats->surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
197 handle->previousReleaseFence);
Marissa Wall3dad52d2019-03-22 14:03:19 -0700198 return NO_ERROR;
Marissa Wallfda30bb2018-10-12 11:34:28 -0700199}
200
201void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
202 std::lock_guard<std::mutex> lock(mMutex);
203 mPresentFence = presentFence;
Marissa Walle2ffb422018-10-12 11:33:52 -0700204}
205
206void TransactionCompletedThread::sendCallbacks() {
207 std::lock_guard lock(mMutex);
208 if (mRunning) {
209 mConditionVariable.notify_all();
210 }
211}
212
213void TransactionCompletedThread::threadMain() {
214 std::lock_guard lock(mMutex);
215
216 while (mKeepRunning) {
217 mConditionVariable.wait(mMutex);
218
219 // For each listener
Marissa Walld600d572019-03-26 15:38:50 -0700220 auto completedTransactionsItr = mCompletedTransactions.begin();
221 while (completedTransactionsItr != mCompletedTransactions.end()) {
222 auto& [listener, transactionStatsDeque] = *completedTransactionsItr;
223 ListenerStats listenerStats;
224 listenerStats.listener = listener;
Marissa Walle2ffb422018-10-12 11:33:52 -0700225
226 // For each transaction
Marissa Walld600d572019-03-26 15:38:50 -0700227 auto transactionStatsItr = transactionStatsDeque.begin();
228 while (transactionStatsItr != transactionStatsDeque.end()) {
229 auto& transactionStats = *transactionStatsItr;
230
231 // If we are still waiting on the callback handles for this transaction, stop
232 // here because all transaction callbacks for the same listener must come in order
233 if (mPendingTransactions[listener].count(transactionStats.callbackIds) != 0) {
Marissa Walle2ffb422018-10-12 11:33:52 -0700234 break;
235 }
Marissa Wallfda30bb2018-10-12 11:34:28 -0700236
237 // If the transaction has been latched
238 if (transactionStats.latchTime >= 0) {
Valerie Hau63258a12018-12-14 14:31:48 -0800239 if (!mPresentFence) {
Marissa Wallfda30bb2018-10-12 11:34:28 -0700240 break;
241 }
Valerie Hau63258a12018-12-14 14:31:48 -0800242 transactionStats.presentFence = mPresentFence;
Marissa Wallfda30bb2018-10-12 11:34:28 -0700243 }
Marissa Walld600d572019-03-26 15:38:50 -0700244
245 // Remove the transaction from completed to the callback
246 listenerStats.transactionStats.push_back(std::move(transactionStats));
247 transactionStatsItr = transactionStatsDeque.erase(transactionStatsItr);
Marissa Walle2ffb422018-10-12 11:33:52 -0700248 }
Marissa Walld600d572019-03-26 15:38:50 -0700249 // If the listener has completed transactions
250 if (!listenerStats.transactionStats.empty()) {
Marissa Walle2ffb422018-10-12 11:33:52 -0700251 // If the listener is still alive
Marissa Walld600d572019-03-26 15:38:50 -0700252 if (IInterface::asBinder(listener)->isBinderAlive()) {
Marissa Walle2ffb422018-10-12 11:33:52 -0700253 // Send callback
254 listenerStats.listener->onTransactionCompleted(listenerStats);
Marissa Walld600d572019-03-26 15:38:50 -0700255 IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient);
Marissa Walle2ffb422018-10-12 11:33:52 -0700256 }
Marissa Walld600d572019-03-26 15:38:50 -0700257 completedTransactionsItr = mCompletedTransactions.erase(completedTransactionsItr);
Marissa Walle2ffb422018-10-12 11:33:52 -0700258 } else {
Marissa Walld600d572019-03-26 15:38:50 -0700259 completedTransactionsItr++;
Marissa Walle2ffb422018-10-12 11:33:52 -0700260 }
261 }
Marissa Wallfda30bb2018-10-12 11:34:28 -0700262
263 if (mPresentFence) {
264 mPresentFence.clear();
Marissa Wallfda30bb2018-10-12 11:34:28 -0700265 }
Marissa Walle2ffb422018-10-12 11:33:52 -0700266 }
267}
268
269// -----------------------------------------------------------------------
270
271CallbackHandle::CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
272 const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
273 : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
274
275} // namespace android