summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jim Shargo <jshargo@google.com> 2024-07-10 23:39:10 +0000
committer Jim Shargo <jshargo@google.com> 2024-08-22 19:48:16 +0000
commita3da302041614624faefd7a4ec8d156dae418043 (patch)
tree59d4a8612fefe1279965a21523eae41a068e8041
parente7b48b55e89ac2682ce7763aa567bf9cd1cc05ae (diff)
Surface: Add a death notification to SurfaceListener
As we move away from IGBPs being available generally, clients may still want to know if the other end of the Surface dies on them. With no binder object available to them, if the client requests it, we wrap the callback in a proxy and notify via SurfaceListener::onRemoteDied when they request it via SurfaceListener::needsDeathNotify. See go/warren-buffers for more details. BYPASS_IGBP_IGBC_API_REASON=warren buffers Bug: 340933794 Flag: com.android.graphics.libgui.flags.wb_platform_api_improvements Test: new tests in libgui_test Change-Id: I102c21436ba3d852481bfa636c5de102ef244e4a
-rw-r--r--libs/gui/Surface.cpp41
-rw-r--r--libs/gui/include/gui/Surface.h32
-rw-r--r--libs/gui/tests/Surface_test.cpp48
3 files changed, 121 insertions, 0 deletions
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index da3886ccf0..76d74fef88 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -77,9 +77,28 @@ bool isInterceptorRegistrationOp(int op) {
} // namespace
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+Surface::ProducerDeathListenerProxy::ProducerDeathListenerProxy(wp<SurfaceListener> surfaceListener)
+ : mSurfaceListener(surfaceListener) {}
+
+void Surface::ProducerDeathListenerProxy::binderDied(const wp<IBinder>&) {
+ sp<SurfaceListener> surfaceListener = mSurfaceListener.promote();
+ if (!surfaceListener) {
+ return;
+ }
+
+ if (surfaceListener->needsDeathNotify()) {
+ surfaceListener->onRemoteDied();
+ }
+}
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
const sp<IBinder>& surfaceControlHandle)
: mGraphicBufferProducer(bufferProducer),
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ mSurfaceDeathListener(nullptr),
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
mCrop(Rect::EMPTY_RECT),
mBufferAge(0),
mGenerationNumber(0),
@@ -134,6 +153,12 @@ Surface::~Surface() {
if (mConnectedToCpu) {
Surface::disconnect(NATIVE_WINDOW_API_CPU);
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (mSurfaceDeathListener != nullptr) {
+ IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener);
+ mSurfaceDeathListener = nullptr;
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
}
sp<ISurfaceComposer> Surface::composerService() const {
@@ -2033,6 +2058,7 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output;
mReportRemovedBuffers = reportBufferRemoval;
+
if (listener != nullptr) {
mListenerProxy = new ProducerListenerProxy(this, listener);
}
@@ -2053,6 +2079,13 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu
}
mConsumerRunningBehind = (output.numPendingBuffers >= 2);
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (listener && listener->needsDeathNotify()) {
+ mSurfaceDeathListener = sp<ProducerDeathListenerProxy>::make(listener);
+ IInterface::asBinder(mGraphicBufferProducer)->linkToDeath(mSurfaceDeathListener);
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
}
if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true;
@@ -2093,6 +2126,14 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) {
mConnectedToCpu = false;
}
}
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (mSurfaceDeathListener != nullptr) {
+ IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener);
+ mSurfaceDeathListener = nullptr;
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
return err;
}
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 0f51f2dc13..5ea81c4c25 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -66,6 +66,16 @@ public:
virtual void onBufferAttached() {}
virtual bool needsAttachNotify() { return false; }
#endif
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ // Called if this Surface is connected to a remote implementation and it
+ // dies or becomes unavailable.
+ virtual void onRemoteDied() {}
+
+ // Clients will overwrite this if they want to receive a notification
+ // via onRemoteDied. This should return a constant value.
+ virtual bool needsDeathNotify() { return false; }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
};
class StubSurfaceListener : public SurfaceListener {
@@ -471,6 +481,21 @@ protected:
sp<SurfaceListener> mSurfaceListener;
};
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ class ProducerDeathListenerProxy : public IBinder::DeathRecipient {
+ public:
+ ProducerDeathListenerProxy(wp<SurfaceListener> surfaceListener);
+ ProducerDeathListenerProxy(ProducerDeathListenerProxy&) = delete;
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>&) override;
+
+ private:
+ wp<SurfaceListener> mSurfaceListener;
+ };
+ friend class ProducerDeathListenerProxy;
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
void querySupportedTimestampsLocked() const;
void freeAllBuffers();
@@ -502,6 +527,13 @@ protected:
// TODO: rename to mBufferProducer
sp<IGraphicBufferProducer> mGraphicBufferProducer;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ // mSurfaceDeathListener gets registered as mGraphicBufferProducer's
+ // DeathRecipient when SurfaceListener::needsDeathNotify returns true and
+ // gets notified when it dies.
+ sp<ProducerDeathListenerProxy> mSurfaceDeathListener;
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
// mSlots stores the buffers that have been allocated for each buffer slot.
// It is initialized to null pointers, and gets filled in with the result of
// IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ab09dfc58d..0c3859ebe0 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -50,7 +50,10 @@
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <chrono>
#include <cstddef>
+#include <cstdint>
+#include <future>
#include <limits>
#include <thread>
@@ -108,6 +111,18 @@ private:
std::vector<sp<GraphicBuffer>> mDiscardedBuffers;
};
+class DeathWatcherListener : public StubSurfaceListener {
+public:
+ virtual void onRemoteDied() { mDiedPromise.set_value(true); }
+
+ virtual bool needsDeathNotify() { return true; }
+
+ std::future<bool> getDiedFuture() { return mDiedPromise.get_future(); }
+
+private:
+ std::promise<bool> mDiedPromise;
+};
+
class SurfaceTest : public ::testing::Test {
protected:
SurfaceTest() {
@@ -2374,6 +2389,39 @@ TEST_F(SurfaceTest, ViewSurface_toString) {
surface.name = String16("name");
EXPECT_EQ("name", surface.toString());
}
+
+TEST_F(SurfaceTest, TestRemoteSurfaceDied_CallbackCalled) {
+ sp<TestServerClient> testServer = TestServerClient::Create();
+ sp<IGraphicBufferProducer> producer = testServer->CreateProducer();
+ EXPECT_NE(nullptr, producer);
+
+ sp<Surface> surface = sp<Surface>::make(producer);
+ sp<DeathWatcherListener> deathWatcher = sp<DeathWatcherListener>::make();
+ EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher));
+
+ auto diedFuture = deathWatcher->getDiedFuture();
+ EXPECT_EQ(OK, testServer->Kill());
+
+ diedFuture.wait();
+ EXPECT_TRUE(diedFuture.get());
+}
+
+TEST_F(SurfaceTest, TestRemoteSurfaceDied_Disconnect_CallbackNotCalled) {
+ sp<TestServerClient> testServer = TestServerClient::Create();
+ sp<IGraphicBufferProducer> producer = testServer->CreateProducer();
+ EXPECT_NE(nullptr, producer);
+
+ sp<Surface> surface = sp<Surface>::make(producer);
+ sp<DeathWatcherListener> deathWatcher = sp<DeathWatcherListener>::make();
+ EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher));
+ EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU));
+
+ auto watcherDiedFuture = deathWatcher->getDiedFuture();
+ EXPECT_EQ(OK, testServer->Kill());
+
+ std::future_status status = watcherDiedFuture.wait_for(std::chrono::seconds(1));
+ EXPECT_EQ(std::future_status::timeout, status);
+}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
} // namespace android