Merge "Surface: Add a death notification to SurfaceListener" into main
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index da3886c..76d74fe 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -77,9 +77,28 @@
 
 } // 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 @@
     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 @@
     Mutex::Autolock lock(mMutex);
     IGraphicBufferProducer::QueueBufferOutput output;
     mReportRemovedBuffers = reportBufferRemoval;
+
     if (listener != nullptr) {
         mListenerProxy = new ProducerListenerProxy(this, listener);
     }
@@ -2053,6 +2079,13 @@
         }
 
         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 @@
             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 0f51f2d..5ea81c4 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -66,6 +66,16 @@
     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 @@
         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 @@
     // 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 ab09dfc..0c3859e 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 @@
     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 @@
     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