summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Williams <pdwilliams@google.com>2023-03-15 15:27:33 -0500
committerPatrick Williams <pdwilliams@google.com>2023-03-22 18:23:44 -0500
commitf3213d2ca821472b12ce2452e4bd33b4cd152e8f (patch)
tree519994613d122b0abe6952dbbe9d1c000af60e78
parentc2286a317e15fba7025c4c6e2059821187d91da6 (diff)
downloadnative-f3213d2ca821472b12ce2452e4bd33b4cd152e8f.tar.gz
SF: throttle WindowInfosListener calls
This change updates WindowInfosListenerInvoker to delay and drop messages when there are unacked messages. When WindowInfosListener calls are acknowledged before the next windowInfosChanged call, there is no behavior change. If windowInfosChanged is called and there are unacked messages, then the update is delayed and sent once the messages are acked via WindowInfosReportedListener. If windowInfosChanged is called and there is already a delayed update, then the previous delayed update is overwritten and only the latest update is sent. WindowInfosListeners are still called immediately when there are focus requests. This means the number of unacked messages may be greater than one. Bug: 270894765 Test: presubmits Test: manual fuzz testing (random sleeps added to input flinger listener) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a364bd7c0ecc412582eff1160368f3eaa2b4c6f0) Merged-In: I78b39b10c52f4e4939f1741516d0edbe9898ef3c Change-Id: I78b39b10c52f4e4939f1741516d0edbe9898ef3c Change-Id: Ib796d8b459d2157b96acdb334404353ca6b1da61
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp7
-rw-r--r--services/surfaceflinger/WindowInfosListenerInvoker.cpp93
-rw-r--r--services/surfaceflinger/WindowInfosListenerInvoker.h12
3 files changed, 85 insertions, 27 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 494aa2c2cf..5db79999c8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3257,8 +3257,11 @@ void SurfaceFlinger::updateInputFlinger() {
inputFlinger = mInputFlinger, this]() {
ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
if (updateWindowInfo) {
- mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
- inputWindowCommands.syncInputWindows);
+ mWindowInfosListenerInvoker
+ ->windowInfosChanged(std::move(windowInfos), std::move(displayInfos),
+ /* shouldSync= */ inputWindowCommands.syncInputWindows,
+ /* forceImmediateCall= */
+ !inputWindowCommands.focusRequests.empty());
} else if (inputWindowCommands.syncInputWindows) {
// If the caller requested to sync input windows, but there are no
// changes to input windows, notify immediately.
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 30b9d8f1cb..023402f747 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -28,19 +28,26 @@ using gui::WindowInfo;
struct WindowInfosListenerInvoker::WindowInfosReportedListener
: gui::BnWindowInfosReportedListener {
- explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker) : mInvoker(invoker) {}
+ explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker, size_t callbackCount,
+ bool shouldSync)
+ : mInvoker(invoker), mCallbacksPending(callbackCount), mShouldSync(shouldSync) {}
binder::Status onWindowInfosReported() override {
- mInvoker.windowInfosReported();
+ mCallbacksPending--;
+ if (mCallbacksPending == 0) {
+ mInvoker.windowInfosReported(mShouldSync);
+ }
return binder::Status::ok();
}
+private:
WindowInfosListenerInvoker& mInvoker;
+ std::atomic<size_t> mCallbacksPending;
+ bool mShouldSync;
};
WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger)
- : mFlinger(flinger),
- mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {}
+ : mFlinger(flinger) {}
void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
@@ -64,30 +71,76 @@ void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) {
mWindowInfosListeners.erase(who);
}
-void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
- const std::vector<DisplayInfo>& displayInfos,
- bool shouldSync) {
- ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
- {
- std::scoped_lock lock(mListenersMutex);
- for (const auto& [_, listener] : mWindowInfosListeners) {
- windowInfosListeners.push_back(listener);
+void WindowInfosListenerInvoker::windowInfosChanged(std::vector<WindowInfo> windowInfos,
+ std::vector<DisplayInfo> displayInfos,
+ bool shouldSync, bool forceImmediateCall) {
+ auto callListeners = [this, windowInfos = std::move(windowInfos),
+ displayInfos = std::move(displayInfos)](bool shouldSync) mutable {
+ ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mWindowInfosListeners) {
+ windowInfosListeners.push_back(listener);
+ }
}
- }
- mCallbacksPending = windowInfosListeners.size();
+ auto reportedListener =
+ sp<WindowInfosReportedListener>::make(*this, windowInfosListeners.size(),
+ shouldSync);
+
+ for (const auto& listener : windowInfosListeners) {
+ auto status =
+ listener->onWindowInfosChanged(windowInfos, displayInfos, reportedListener);
+ if (!status.isOk()) {
+ reportedListener->onWindowInfosReported();
+ }
+ }
+ };
+
+ {
+ 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);
+ mShouldSyncDelayed |= shouldSync;
+ return;
+ }
- for (const auto& listener : windowInfosListeners) {
- listener->onWindowInfosChanged(windowInfos, displayInfos,
- shouldSync ? mWindowInfosReportedListener : nullptr);
+ mWindowInfosChangedDelayed = nullptr;
+ shouldSync |= mShouldSyncDelayed;
+ mShouldSyncDelayed = false;
+ mActiveMessageCount++;
}
+ callListeners(shouldSync);
}
-void WindowInfosListenerInvoker::windowInfosReported() {
- mCallbacksPending--;
- if (mCallbacksPending == 0) {
+void WindowInfosListenerInvoker::windowInfosReported(bool shouldSync) {
+ if (shouldSync) {
mFlinger.windowInfosReported();
}
+
+ std::function<void(bool)> callListeners;
+ bool shouldSyncDelayed;
+ {
+ std::scoped_lock lock{mMessagesMutex};
+ mActiveMessageCount--;
+ if (!mWindowInfosChangedDelayed || mActiveMessageCount > 0) {
+ return;
+ }
+
+ mActiveMessageCount++;
+ callListeners = std::move(mWindowInfosChangedDelayed);
+ mWindowInfosChangedDelayed = nullptr;
+ shouldSyncDelayed = mShouldSyncDelayed;
+ mShouldSyncDelayed = false;
+ }
+
+ callListeners(shouldSyncDelayed);
}
} // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index d8d8d0f570..701f11efcd 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -34,15 +34,15 @@ 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>&, bool shouldSync);
+ void windowInfosChanged(std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>,
+ bool shouldSync, bool forceImmediateCall);
protected:
void binderDied(const wp<IBinder>& who) override;
private:
struct WindowInfosReportedListener;
- void windowInfosReported();
+ void windowInfosReported(bool shouldSync);
SurfaceFlinger& mFlinger;
std::mutex mListenersMutex;
@@ -51,8 +51,10 @@ private:
ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
- sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
- std::atomic<size_t> mCallbacksPending{0};
+ std::mutex mMessagesMutex;
+ uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0;
+ std::function<void(bool)> mWindowInfosChangedDelayed GUARDED_BY(mMessagesMutex);
+ bool mShouldSyncDelayed;
};
} // namespace android