diff options
Diffstat (limited to 'services/surfaceflinger/WindowInfosListenerInvoker.cpp')
-rw-r--r-- | services/surfaceflinger/WindowInfosListenerInvoker.cpp | 253 |
1 files changed, 130 insertions, 123 deletions
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 20699ef123..7062a4e3a7 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <ftl/small_vector.h> +#include <android/gui/BnWindowInfosPublisher.h> +#include <android/gui/IWindowInfosPublisher.h> +#include <android/gui/WindowInfosListenerInfo.h> #include <gui/ISurfaceComposer.h> #include <gui/TraceUtils.h> #include <gui/WindowInfosUpdate.h> @@ -23,162 +25,130 @@ #include "BackgroundExecutor.h" #include "WindowInfosListenerInvoker.h" +#undef ATRACE_TAG +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + namespace android { using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -using WindowInfosListenerVector = ftl::SmallVector<const sp<gui::IWindowInfosListener>, 3>; - -struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener, - IBinder::DeathRecipient { - WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners, - WindowInfosReportedListenerSet windowInfosReportedListeners) - : mCallbacksPending(windowInfosListeners.size()), - mWindowInfosListeners(std::move(windowInfosListeners)), - mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {} +void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener, + gui::WindowInfosListenerInfo* outInfo) { + int64_t listenerId = mNextListenerId++; + outInfo->listenerId = listenerId; + outInfo->windowInfosPublisher = sp<gui::IWindowInfosPublisher>::fromExisting(this); - binder::Status onWindowInfosReported() override { - if (--mCallbacksPending == 0) { - for (const auto& listener : mWindowInfosReportedListeners) { + BackgroundExecutor::getInstance().sendCallbacks( + {[this, listener = std::move(listener), listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::addWindowInfosListener"); sp<IBinder> asBinder = IInterface::asBinder(listener); - if (asBinder->isBinderAlive()) { - listener->onWindowInfosReported(); - } - } - - auto wpThis = wp<WindowInfosReportedListenerInvoker>::fromExisting(this); - for (const auto& listener : mWindowInfosListeners) { - sp<IBinder> binder = IInterface::asBinder(listener); - binder->unlinkToDeath(wpThis); - } - } - return binder::Status::ok(); - } - - void binderDied(const wp<IBinder>&) { onWindowInfosReported(); } - -private: - std::atomic<size_t> mCallbacksPending; - static constexpr size_t kStaticCapacity = 3; - const WindowInfosListenerVector mWindowInfosListeners; - WindowInfosReportedListenerSet mWindowInfosReportedListeners; -}; - -void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) { - sp<IBinder> asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); - - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.try_emplace(asBinder, std::move(listener)); + asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this)); + mWindowInfosListeners.try_emplace(asBinder, + std::make_pair(listenerId, std::move(listener))); + }}); } void WindowInfosListenerInvoker::removeWindowInfosListener( const sp<IWindowInfosListener>& listener) { - sp<IBinder> asBinder = IInterface::asBinder(listener); - - std::scoped_lock lock(mListenersMutex); - asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this)); - mWindowInfosListeners.erase(asBinder); + BackgroundExecutor::getInstance().sendCallbacks({[this, listener]() { + ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener"); + sp<IBinder> asBinder = IInterface::asBinder(listener); + asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this)); + mWindowInfosListeners.erase(asBinder); + }}); } void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) { - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.erase(who); + BackgroundExecutor::getInstance().sendCallbacks({[this, who]() { + ATRACE_NAME("WindowInfosListenerInvoker::binderDied"); + auto it = mWindowInfosListeners.find(who); + int64_t listenerId = it->second.first; + mWindowInfosListeners.erase(who); + + std::vector<int64_t> vsyncIds; + for (auto& [vsyncId, state] : mUnackedState) { + if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), + listenerId) != state.unackedListenerIds.end()) { + vsyncIds.push_back(vsyncId); + } + } + + for (int64_t vsyncId : vsyncIds) { + ackWindowInfosReceived(vsyncId, listenerId); + } + }}); } void WindowInfosListenerInvoker::windowInfosChanged( gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) { - WindowInfosListenerVector listeners; - { - std::scoped_lock lock{mMessagesMutex}; - - if (!mDelayInfo) { - mDelayInfo = DelayInfo{ - .vsyncId = update.vsyncId, - .frameTime = update.timestamp, - }; - } - - // If there are unacked messages and this isn't a forced call, then return immediately. - // If a forced window infos change doesn't happen first, the update will be sent after - // the WindowInfosReportedListeners are called. If a forced window infos change happens or - // if there are subsequent delayed messages before this update is sent, then this message - // will be dropped and the listeners will only be called with the latest info. This is done - // to reduce the amount of binder memory used. - if (mActiveMessageCount > 0 && !forceImmediateCall) { - mDelayedUpdate = std::move(update); - mReportedListeners.merge(reportedListeners); - return; - } - - if (mDelayedUpdate) { - mDelayedUpdate.reset(); - } + if (!mDelayInfo) { + mDelayInfo = DelayInfo{ + .vsyncId = update.vsyncId, + .frameTime = update.timestamp, + }; + } - { - std::scoped_lock lock{mListenersMutex}; - for (const auto& [_, listener] : mWindowInfosListeners) { - listeners.push_back(listener); - } - } - if (CC_UNLIKELY(listeners.empty())) { - mReportedListeners.merge(reportedListeners); - mDelayInfo.reset(); - return; - } + // If there are unacked messages and this isn't a forced call, then return immediately. + // If a forced window infos change doesn't happen first, the update will be sent after + // the WindowInfosReportedListeners are called. If a forced window infos change happens or + // if there are subsequent delayed messages before this update is sent, then this message + // will be dropped and the listeners will only be called with the latest info. This is done + // to reduce the amount of binder memory used. + if (!mUnackedState.empty() && !forceImmediateCall) { + mDelayedUpdate = std::move(update); + mReportedListeners.merge(reportedListeners); + return; + } - reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this)); - reportedListeners.merge(mReportedListeners); - mReportedListeners.clear(); + if (mDelayedUpdate) { + mDelayedUpdate.reset(); + } - mActiveMessageCount++; - updateMaxSendDelay(); + if (CC_UNLIKELY(mWindowInfosListeners.empty())) { + mReportedListeners.merge(reportedListeners); mDelayInfo.reset(); + return; } - auto reportedInvoker = - sp<WindowInfosReportedListenerInvoker>::make(listeners, std::move(reportedListeners)); - - for (const auto& listener : listeners) { - sp<IBinder> asBinder = IInterface::asBinder(listener); + reportedListeners.merge(mReportedListeners); + mReportedListeners.clear(); + + // Update mUnackedState to include the message we're about to send + auto [it, _] = mUnackedState.try_emplace(update.vsyncId, + UnackedState{.reportedListeners = + std::move(reportedListeners)}); + auto& unackedState = it->second; + for (auto& pair : mWindowInfosListeners) { + int64_t listenerId = pair.second.first; + unackedState.unackedListenerIds.push_back(listenerId); + } - // linkToDeath is used here to ensure that the windowInfosReportedListeners - // are called even if one of the windowInfosListeners dies before - // calling onWindowInfosReported. - asBinder->linkToDeath(reportedInvoker); + mDelayInfo.reset(); + updateMaxSendDelay(); - auto status = listener->onWindowInfosChanged(update, reportedInvoker); + // Call the listeners + for (auto& pair : mWindowInfosListeners) { + auto& [listenerId, listener] = pair.second; + auto status = listener->onWindowInfosChanged(update); if (!status.isOk()) { - reportedInvoker->onWindowInfosReported(); + ackWindowInfosReceived(update.vsyncId, listenerId); } } } -binder::Status WindowInfosListenerInvoker::onWindowInfosReported() { - BackgroundExecutor::getInstance().sendCallbacks({[this]() { - gui::WindowInfosUpdate update; - { - std::scoped_lock lock{mMessagesMutex}; - mActiveMessageCount--; - if (!mDelayedUpdate || mActiveMessageCount > 0) { - return; - } - update = std::move(*mDelayedUpdate); - mDelayedUpdate.reset(); - } - windowInfosChanged(std::move(update), {}, false); - }}); - return binder::Status::ok(); -} - WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() { - std::scoped_lock lock{mMessagesMutex}; - updateMaxSendDelay(); - mDebugInfo.pendingMessageCount = mActiveMessageCount; - return mDebugInfo; + DebugInfo result; + BackgroundExecutor::getInstance().sendCallbacks({[&, this]() { + ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo"); + updateMaxSendDelay(); + result = mDebugInfo; + result.pendingMessageCount = mUnackedState.size(); + }}); + BackgroundExecutor::getInstance().flushQueue(); + return result; } void WindowInfosListenerInvoker::updateMaxSendDelay() { @@ -192,4 +162,41 @@ void WindowInfosListenerInvoker::updateMaxSendDelay() { } } +binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId, + int64_t listenerId) { + BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived"); + auto it = mUnackedState.find(vsyncId); + if (it == mUnackedState.end()) { + return; + } + + auto& state = it->second; + state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(), + state.unackedListenerIds.end(), + listenerId)); + if (!state.unackedListenerIds.empty()) { + return; + } + + WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)}; + mUnackedState.erase(vsyncId); + + for (const auto& reportedListener : reportedListeners) { + sp<IBinder> asBinder = IInterface::asBinder(reportedListener); + if (asBinder->isBinderAlive()) { + reportedListener->onWindowInfosReported(); + } + } + + if (!mDelayedUpdate || !mUnackedState.empty()) { + return; + } + gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)}; + mDelayedUpdate.reset(); + windowInfosChanged(std::move(update), {}, false); + }}); + return binder::Status::ok(); +} + } // namespace android |