Merge "SF: throttle WindowInfosListener calls" into udc-dev
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a538c6d..9c232b1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2442,16 +2442,7 @@
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 acdd01d..8d7c362 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -372,6 +372,21 @@
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 8394ffb..31bf7ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3715,17 +3715,33 @@
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 d1acc86..eb9dc74 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1424,6 +1424,11 @@
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 292083b..856fbbb 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -25,20 +25,17 @@
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 @@
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 @@
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::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));
+}
+
+binder::Status WindowInfosListenerInvoker::onWindowInfosReported() {
+ std::function<void(WindowInfosReportedListenerSet)> callListeners;
+ WindowInfosReportedListenerSet reportedListeners;
+
+ {
+ 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();
}
- 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);
- }
-
- auto status = listener->onWindowInfosChanged(windowInfos, displayInfos,
- windowInfosReportedListener);
- if (windowInfosReportedListener && !status.isOk()) {
- windowInfosReportedListener->onWindowInfosReported();
- }
- }
+ callListeners(std::move(reportedListeners));
+ return binder::Status::ok();
}
} // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index d60a9c4..4da9828 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