/* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "TransactionCompletedThread" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "TransactionCompletedThread.h" #include #include #include #include namespace android { TransactionCompletedThread::~TransactionCompletedThread() { std::lock_guard lockThread(mThreadMutex); { std::lock_guard lock(mMutex); mKeepRunning = false; mConditionVariable.notify_all(); } if (mThread.joinable()) { mThread.join(); } { std::lock_guard lock(mMutex); for (const auto& [listener, listenerStats] : mListenerStats) { listener->unlinkToDeath(mDeathRecipient); } } } void TransactionCompletedThread::run() { std::lock_guard lock(mMutex); if (mRunning || !mKeepRunning) { return; } mDeathRecipient = new ThreadDeathRecipient(); mRunning = true; std::lock_guard lockThread(mThreadMutex); mThread = std::thread(&TransactionCompletedThread::threadMain, this); } void TransactionCompletedThread::registerPendingCallbackHandle(const sp& handle) { std::lock_guard lock(mMutex); sp listener = IInterface::asBinder(handle->listener); const auto& callbackIds = handle->callbackIds; mPendingTransactions[listener][callbackIds]++; } void TransactionCompletedThread::addPresentedCallbackHandles( const std::deque>& handles) { std::lock_guard lock(mMutex); for (const auto& handle : handles) { auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener)); auto& pendingCallbacks = listener->second; auto pendingCallback = pendingCallbacks.find(handle->callbackIds); if (pendingCallback != pendingCallbacks.end()) { auto& pendingCount = pendingCallback->second; // Decrease the pending count for this listener if (--pendingCount == 0) { pendingCallbacks.erase(pendingCallback); } } else { ALOGE("there are more latched callbacks than there were registered callbacks"); } addCallbackHandle(handle); } } void TransactionCompletedThread::addUnpresentedCallbackHandle(const sp& handle) { std::lock_guard lock(mMutex); addCallbackHandle(handle); } void TransactionCompletedThread::addCallback( const sp& transactionListener, const std::vector& callbackIds) { std::lock_guard lock(mMutex); addCallbackLocked(transactionListener, callbackIds); } status_t TransactionCompletedThread::addCallbackHandle(const sp& handle) { status_t err = addCallbackLocked(handle->listener, handle->callbackIds); if (err != NO_ERROR) { ALOGE("cannot add callback, err: %d", err); return err; } const sp listener = IInterface::asBinder(handle->listener); auto& listenerStats = mListenerStats[listener]; auto& transactionStats = listenerStats.transactionStats[handle->callbackIds]; transactionStats.latchTime = handle->latchTime; transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime, handle->previousReleaseFence); return NO_ERROR; } status_t TransactionCompletedThread::addCallbackLocked( const sp& transactionListener, const std::vector& callbackIds) { const sp listener = IInterface::asBinder(transactionListener); // If we don't already have a reference to this listener, linkToDeath so we get a notification // if it dies. if (mListenerStats.count(listener) == 0) { status_t err = listener->linkToDeath(mDeathRecipient); if (err != NO_ERROR) { ALOGE("cannot add callback because linkToDeath failed, err: %d", err); return err; } } auto& listenerStats = mListenerStats[listener]; listenerStats.listener = transactionListener; listenerStats.transactionStats[callbackIds]; return NO_ERROR; } void TransactionCompletedThread::addPresentFence(const sp& presentFence) { std::lock_guard lock(mMutex); mPresentFence = presentFence; } void TransactionCompletedThread::sendCallbacks() { std::lock_guard lock(mMutex); if (mRunning) { mConditionVariable.notify_all(); } } void TransactionCompletedThread::threadMain() { std::lock_guard lock(mMutex); while (mKeepRunning) { mConditionVariable.wait(mMutex); // For each listener auto it = mListenerStats.begin(); while (it != mListenerStats.end()) { auto& [listener, listenerStats] = *it; // For each transaction bool sendCallback = true; for (auto& [callbackIds, transactionStats] : listenerStats.transactionStats) { // If we are still waiting on the callback handles for this transaction, skip it if (mPendingTransactions[listener].count(callbackIds) != 0) { sendCallback = false; break; } // If the transaction has been latched if (transactionStats.latchTime >= 0) { if (!mPresentFence) { sendCallback = false; break; } transactionStats.presentFence = mPresentFence; } } // If the listener has no pending transactions and all latched transactions have been // presented if (sendCallback) { // If the listener is still alive if (listener->isBinderAlive()) { // Send callback listenerStats.listener->onTransactionCompleted(listenerStats); listener->unlinkToDeath(mDeathRecipient); } it = mListenerStats.erase(it); } else { it++; } } if (mPresentFence) { mPresentFence.clear(); } } } // ----------------------------------------------------------------------- CallbackHandle::CallbackHandle(const sp& transactionListener, const std::vector& ids, const sp& sc) : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {} } // namespace android