Fix WindowInfosListenerTest
Fixes a race condition where the WindowInfo vector checked may not
contain the updated window on the first pass.
Bug: 269522974
Test: atest WindowInfosListenerTest
Change-Id: I013955dd1c89858190b519c2980909e2e7e45a24
(cherry picked from commit 4c766ae50ce641672158c19eda4613a5e64baf47)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c91ad49..28b7dd6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3576,6 +3576,10 @@
});
}
+ if (transactionFlags & eInputInfoUpdateNeeded) {
+ mUpdateInputInfo = true;
+ }
+
doCommitTransactions();
}
@@ -7567,8 +7571,9 @@
}
status_t SurfaceFlinger::addWindowInfosListener(
- const sp<IWindowInfosListener>& windowInfosListener) const {
+ const sp<IWindowInfosListener>& windowInfosListener) {
mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener);
+ setTransactionFlags(eInputInfoUpdateNeeded);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b41f414..03c31bb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -162,7 +162,8 @@
eDisplayTransactionNeeded = 0x04,
eTransformHintUpdateNeeded = 0x08,
eTransactionFlushNeeded = 0x10,
- eTransactionMask = 0x1f,
+ eInputInfoUpdateNeeded = 0x20,
+ eTransactionMask = 0x3f,
};
// Latch Unsignaled buffer behaviours
@@ -618,7 +619,7 @@
status_t getMaxAcquiredBufferCount(int* buffers) const;
- status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener) const;
+ status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
status_t removeWindowInfosListener(
const sp<gui::IWindowInfosListener>& windowInfosListener) const;
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index a1313e3..292083b 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -17,7 +17,6 @@
#include <ftl/small_vector.h>
#include <gui/ISurfaceComposer.h>
-#include "SurfaceFlinger.h"
#include "WindowInfosListenerInvoker.h"
namespace android {
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index a1d66a1..d60a9c4 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -16,6 +16,8 @@
#pragma once
+#include <unordered_set>
+
#include <android/gui/BnWindowInfosReportedListener.h>
#include <android/gui/IWindowInfosListener.h>
#include <android/gui/IWindowInfosReportedListener.h>
@@ -49,8 +51,6 @@
static constexpr size_t kStaticCapacity = 3;
ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
-
- sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index 53c3c39..d71486f 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -18,61 +18,61 @@
#include <gui/SurfaceComposerClient.h>
#include <private/android_filesystem_config.h>
#include <future>
-#include "utils/TransactionUtils.h"
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
using gui::DisplayInfo;
using gui::WindowInfo;
+using WindowInfosPredicate = std::function<bool(const std::vector<WindowInfo>&)>;
+
class WindowInfosListenerTest : public ::testing::Test {
protected:
void SetUp() override {
seteuid(AID_SYSTEM);
mClient = sp<SurfaceComposerClient>::make();
- mWindowInfosListener = sp<SyncWindowInfosListener>::make();
- mClient->addWindowInfosListener(mWindowInfosListener);
}
- void TearDown() override {
- mClient->removeWindowInfosListener(mWindowInfosListener);
- seteuid(AID_ROOT);
- }
+ void TearDown() override { seteuid(AID_ROOT); }
- struct SyncWindowInfosListener : public gui::WindowInfosListener {
+ struct WindowInfosListener : public gui::WindowInfosListener {
public:
+ WindowInfosListener(WindowInfosPredicate predicate, std::promise<void>& promise)
+ : mPredicate(std::move(predicate)), mPromise(promise) {}
+
void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,
const std::vector<DisplayInfo>&) override {
- windowInfosPromise.set_value(windowInfos);
- }
-
- std::vector<WindowInfo> waitForWindowInfos() {
- std::future<std::vector<WindowInfo>> windowInfosFuture =
- windowInfosPromise.get_future();
- std::vector<WindowInfo> windowInfos = windowInfosFuture.get();
- windowInfosPromise = std::promise<std::vector<WindowInfo>>();
- return windowInfos;
+ if (mPredicate(windowInfos)) {
+ mPromise.set_value();
+ }
}
private:
- std::promise<std::vector<WindowInfo>> windowInfosPromise;
+ WindowInfosPredicate mPredicate;
+ std::promise<void>& mPromise;
};
sp<SurfaceComposerClient> mClient;
- sp<SyncWindowInfosListener> mWindowInfosListener;
+
+ bool waitForWindowInfosPredicate(WindowInfosPredicate predicate) {
+ std::promise<void> promise;
+ auto listener = sp<WindowInfosListener>::make(std::move(predicate), promise);
+ mClient->addWindowInfosListener(listener);
+ auto future = promise.get_future();
+ bool satisfied = future.wait_for(std::chrono::seconds{1}) == std::future_status::ready;
+ mClient->removeWindowInfosListener(listener);
+ return satisfied;
+ }
};
std::optional<WindowInfo> findMatchingWindowInfo(WindowInfo targetWindowInfo,
std::vector<WindowInfo> windowInfos) {
- std::optional<WindowInfo> foundWindowInfo = std::nullopt;
for (WindowInfo windowInfo : windowInfos) {
if (windowInfo.token == targetWindowInfo.token) {
- foundWindowInfo = std::make_optional<>(windowInfo);
- break;
+ return windowInfo;
}
}
-
- return foundWindowInfo;
+ return std::nullopt;
}
TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) {
@@ -92,15 +92,17 @@
.setInputWindowInfo(surfaceControl, windowInfo)
.apply();
- std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos();
- std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
- ASSERT_NE(std::nullopt, foundWindowInfo);
+ auto windowPresent = [&](const std::vector<WindowInfo>& windowInfos) {
+ return findMatchingWindowInfo(windowInfo, windowInfos).has_value();
+ };
+ ASSERT_TRUE(waitForWindowInfosPredicate(windowPresent));
Transaction().reparent(surfaceControl, nullptr).apply();
- windowInfos = mWindowInfosListener->waitForWindowInfos();
- foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
- ASSERT_EQ(std::nullopt, foundWindowInfo);
+ auto windowNotPresent = [&](const std::vector<WindowInfo>& windowInfos) {
+ return !findMatchingWindowInfo(windowInfo, windowInfos).has_value();
+ };
+ ASSERT_TRUE(waitForWindowInfosPredicate(windowNotPresent));
}
TEST_F(WindowInfosListenerTest, WindowInfoChanged) {
@@ -121,19 +123,28 @@
.setInputWindowInfo(surfaceControl, windowInfo)
.apply();
- std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos();
- std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
- ASSERT_NE(std::nullopt, foundWindowInfo);
- ASSERT_TRUE(foundWindowInfo->touchableRegion.isEmpty());
+ auto windowIsPresentAndTouchableRegionEmpty = [&](const std::vector<WindowInfo>& windowInfos) {
+ auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ if (!foundWindowInfo) {
+ return false;
+ }
+ return foundWindowInfo->touchableRegion.isEmpty();
+ };
+ ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionEmpty));
Rect touchableRegions(0, 0, 50, 50);
windowInfo.addTouchableRegion(Rect(0, 0, 50, 50));
Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply();
- windowInfos = mWindowInfosListener->waitForWindowInfos();
- foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
- ASSERT_NE(std::nullopt, foundWindowInfo);
- ASSERT_TRUE(foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion));
+ auto windowIsPresentAndTouchableRegionMatches =
+ [&](const std::vector<WindowInfo>& windowInfos) {
+ auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ if (!foundWindowInfo) {
+ return false;
+ }
+ return foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion);
+ };
+ ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionMatches));
}
} // namespace android