diff options
author | 2023-04-16 00:00:40 +0000 | |
---|---|---|
committer | 2023-04-16 00:00:40 +0000 | |
commit | ce2205fc6ff1eaf93bbb00df90df0e02e42a9f2c (patch) | |
tree | 38bcda8ad9fdded152c18a1bdb2835dc21b72da4 | |
parent | cd5edad6c2ee8174f9813836bb5044378fa7e70b (diff) | |
parent | 1caf3b7d82024c9814b5ca41b144c193ade5da26 (diff) |
Merge "SF: throttle WindowInfosListener calls" into udc-dev
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 11 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.h | 15 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 22 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 5 | ||||
-rw-r--r-- | services/surfaceflinger/WindowInfosListenerInvoker.cpp | 126 | ||||
-rw-r--r-- | services/surfaceflinger/WindowInfosListenerInvoker.h | 26 |
6 files changed, 143 insertions, 62 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a538c6d6fb..9c232b11a7 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2442,16 +2442,7 @@ WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) { info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE; } - // For compatibility reasons we let layers which can receive input - // receive input before they have actually submitted a buffer. Because - // of this we use canReceiveInput instead of isVisible to check the - // policy-visibility, ignoring the buffer state. However for layers with - // hasInputInfo()==false we can use the real visibility state. - // We are just using these layers for occlusion detection in - // InputDispatcher, and obviously if they aren't visible they can't occlude - // anything. - const bool visible = hasInputInfo() ? canReceiveInput() : isVisible(); - info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible); + info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !isVisibleForInput()); info.alpha = getAlpha(); fillTouchOcclusionMode(info); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index acdd01da77..8d7c362241 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -372,6 +372,21 @@ public: bool canReceiveInput() const; /* + * Whether or not the layer should be considered visible for input calculations. + */ + virtual bool isVisibleForInput() const { + // For compatibility reasons we let layers which can receive input + // receive input before they have actually submitted a buffer. Because + // of this we use canReceiveInput instead of isVisible to check the + // policy-visibility, ignoring the buffer state. However for layers with + // hasInputInfo()==false we can use the real visibility state. + // We are just using these layers for occlusion detection in + // InputDispatcher, and obviously if they aren't visible they can't occlude + // anything. + return hasInputInfo() ? canReceiveInput() : isVisible(); + } + + /* * isProtected - true if the layer may contain protected contents in the * GRALLOC_USAGE_PROTECTED sense. */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8394ffbca8..31bf7ef70b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3715,17 +3715,33 @@ void SurfaceFlinger::updateInputFlinger() { return; } + std::unordered_set<Layer*> visibleLayers; + mDrawingState.traverse([&visibleLayers](Layer* layer) { + if (layer->isVisibleForInput()) { + visibleLayers.insert(layer); + } + }); + bool visibleLayersChanged = false; + if (visibleLayers != mVisibleLayers) { + visibleLayersChanged = true; + mVisibleLayers = std::move(visibleLayers); + } + BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo, windowInfos = std::move(windowInfos), displayInfos = std::move(displayInfos), inputWindowCommands = std::move(mInputWindowCommands), - inputFlinger = mInputFlinger, this]() { + inputFlinger = mInputFlinger, this, + visibleLayersChanged]() { ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); if (updateWindowInfo) { mWindowInfosListenerInvoker - ->windowInfosChanged(windowInfos, displayInfos, - inputWindowCommands.windowInfosReportedListeners); + ->windowInfosChanged(std::move(windowInfos), std::move(displayInfos), + std::move( + inputWindowCommands.windowInfosReportedListeners), + /* forceImmediateCall= */ visibleLayersChanged || + !inputWindowCommands.focusRequests.empty()); } else { // If there are listeners but no changes to input windows, call the listeners // immediately. diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d1acc86e81..eb9dc7494e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1424,6 +1424,11 @@ private: TransactionHandler mTransactionHandler; display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos; bool mFrontEndDisplayInfosChanged = false; + + // Layers visible during the last commit. This set should only be used for testing set equality + // and membership. The pointers should not be dereferenced as it's possible the set contains + // pointers to freed layers. + std::unordered_set<Layer*> mVisibleLayers; }; class SurfaceComposerAIDL : public gui::BnSurfaceComposer { diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 292083b9bc..856fbbbf33 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -25,20 +25,17 @@ using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener, - DeathRecipient { - explicit WindowInfosReportedListener( - size_t callbackCount, - const std::unordered_set<sp<gui::IWindowInfosReportedListener>, - SpHash<gui::IWindowInfosReportedListener>>& - windowInfosReportedListeners) - : mCallbacksPending(callbackCount), - mWindowInfosReportedListeners(windowInfosReportedListeners) {} +using WindowInfosListenerVector = ftl::SmallVector<const sp<IWindowInfosListener>, 3>; + +struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener, + IBinder::DeathRecipient { + WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners, + WindowInfosReportedListenerSet windowInfosReportedListeners) + : mCallbacksPending(windowInfosListeners.size()), + mWindowInfosListeners(std::move(windowInfosListeners)), + mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {} binder::Status onWindowInfosReported() override { - // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for - // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter - // the list of callbacks down to those from system server. if (--mCallbacksPending == 0) { for (const auto& listener : mWindowInfosReportedListeners) { sp<IBinder> asBinder = IInterface::asBinder(listener); @@ -46,6 +43,12 @@ struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowIn 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(); } @@ -54,9 +57,9 @@ struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowIn private: std::atomic<size_t> mCallbacksPending; - std::unordered_set<sp<gui::IWindowInfosReportedListener>, - SpHash<gui::IWindowInfosReportedListener>> - mWindowInfosReportedListeners; + static constexpr size_t kStaticCapacity = 3; + const WindowInfosListenerVector mWindowInfosListeners; + WindowInfosReportedListenerSet mWindowInfosReportedListeners; }; void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) { @@ -82,38 +85,81 @@ void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) { } void WindowInfosListenerInvoker::windowInfosChanged( - const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos, - const std::unordered_set<sp<gui::IWindowInfosReportedListener>, - SpHash<gui::IWindowInfosReportedListener>>& - windowInfosReportedListeners) { - ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners; + std::vector<WindowInfo> windowInfos, std::vector<DisplayInfo> displayInfos, + WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) { + reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this)); + auto callListeners = [this, windowInfos = std::move(windowInfos), + displayInfos = std::move(displayInfos)]( + WindowInfosReportedListenerSet reportedListeners) mutable { + WindowInfosListenerVector windowInfosListeners; + { + std::scoped_lock lock(mListenersMutex); + for (const auto& [_, listener] : mWindowInfosListeners) { + windowInfosListeners.push_back(listener); + } + } + + auto reportedInvoker = + sp<WindowInfosReportedListenerInvoker>::make(windowInfosListeners, + std::move(reportedListeners)); + + for (const auto& listener : windowInfosListeners) { + sp<IBinder> asBinder = IInterface::asBinder(listener); + + // linkToDeath is used here to ensure that the windowInfosReportedListeners + // are called even if one of the windowInfosListeners dies before + // calling onWindowInfosReported. + asBinder->linkToDeath(reportedInvoker); + + auto status = + listener->onWindowInfosChanged(windowInfos, displayInfos, reportedInvoker); + if (!status.isOk()) { + reportedInvoker->onWindowInfosReported(); + } + } + }; + { - std::scoped_lock lock(mListenersMutex); - for (const auto& [_, listener] : mWindowInfosListeners) { - windowInfosListeners.push_back(listener); + std::scoped_lock lock(mMessagesMutex); + // 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) { + mWindowInfosChangedDelayed = std::move(callListeners); + mReportedListenersDelayed.merge(reportedListeners); + return; } + + mWindowInfosChangedDelayed = nullptr; + reportedListeners.merge(mReportedListenersDelayed); + mActiveMessageCount++; } + callListeners(std::move(reportedListeners)); +} - auto windowInfosReportedListener = windowInfosReportedListeners.empty() - ? nullptr - : sp<WindowInfosReportedListener>::make(windowInfosListeners.size(), - windowInfosReportedListeners); - for (const auto& listener : windowInfosListeners) { - sp<IBinder> asBinder = IInterface::asBinder(listener); - - // linkToDeath is used here to ensure that the windowInfosReportedListeners - // are called even if one of the windowInfosListeners dies before - // calling onWindowInfosReported. - if (windowInfosReportedListener) { - asBinder->linkToDeath(windowInfosReportedListener); - } +binder::Status WindowInfosListenerInvoker::onWindowInfosReported() { + std::function<void(WindowInfosReportedListenerSet)> callListeners; + WindowInfosReportedListenerSet reportedListeners; - auto status = listener->onWindowInfosChanged(windowInfos, displayInfos, - windowInfosReportedListener); - if (windowInfosReportedListener && !status.isOk()) { - windowInfosReportedListener->onWindowInfosReported(); + { + std::scoped_lock lock{mMessagesMutex}; + mActiveMessageCount--; + if (!mWindowInfosChangedDelayed || mActiveMessageCount > 0) { + return binder::Status::ok(); } + + mActiveMessageCount++; + callListeners = std::move(mWindowInfosChangedDelayed); + mWindowInfosChangedDelayed = nullptr; + reportedListeners = std::move(mReportedListenersDelayed); + mReportedListenersDelayed.clear(); } + + callListeners(std::move(reportedListeners)); + return binder::Status::ok(); } } // namespace android diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index d60a9c4157..4da98282a9 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -23,34 +23,42 @@ #include <android/gui/IWindowInfosReportedListener.h> #include <binder/IBinder.h> #include <ftl/small_map.h> +#include <gui/SpHash.h> #include <utils/Mutex.h> namespace android { -class SurfaceFlinger; +using WindowInfosReportedListenerSet = + std::unordered_set<sp<gui::IWindowInfosReportedListener>, + gui::SpHash<gui::IWindowInfosReportedListener>>; -class WindowInfosListenerInvoker : public IBinder::DeathRecipient { +class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener, + public IBinder::DeathRecipient { public: void addWindowInfosListener(sp<gui::IWindowInfosListener>); void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener); - void windowInfosChanged(const std::vector<gui::WindowInfo>&, - const std::vector<gui::DisplayInfo>&, - const std::unordered_set<sp<gui::IWindowInfosReportedListener>, - SpHash<gui::IWindowInfosReportedListener>>& - windowInfosReportedListeners); + void windowInfosChanged(std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>, + WindowInfosReportedListenerSet windowInfosReportedListeners, + bool forceImmediateCall); + + binder::Status onWindowInfosReported() override; protected: void binderDied(const wp<IBinder>& who) override; private: - struct WindowInfosReportedListener; - std::mutex mListenersMutex; static constexpr size_t kStaticCapacity = 3; ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity> mWindowInfosListeners GUARDED_BY(mListenersMutex); + + std::mutex mMessagesMutex; + uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0; + std::function<void(WindowInfosReportedListenerSet)> mWindowInfosChangedDelayed + GUARDED_BY(mMessagesMutex); + WindowInfosReportedListenerSet mReportedListenersDelayed; }; } // namespace android |