Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3da3020 authored by Jim Shargo's avatar Jim Shargo
Browse files

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
parent e7b48b55
Loading
Loading
Loading
Loading
+41 −0
Original line number Original line Diff line number Diff line
@@ -77,9 +77,28 @@ bool isInterceptorRegistrationOp(int op) {


} // namespace
} // 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,
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
                 const sp<IBinder>& surfaceControlHandle)
                 const sp<IBinder>& surfaceControlHandle)
      : mGraphicBufferProducer(bufferProducer),
      : 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),
        mCrop(Rect::EMPTY_RECT),
        mBufferAge(0),
        mBufferAge(0),
        mGenerationNumber(0),
        mGenerationNumber(0),
@@ -134,6 +153,12 @@ Surface::~Surface() {
    if (mConnectedToCpu) {
    if (mConnectedToCpu) {
        Surface::disconnect(NATIVE_WINDOW_API_CPU);
        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 {
sp<ISurfaceComposer> Surface::composerService() const {
@@ -2033,6 +2058,7 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu
    Mutex::Autolock lock(mMutex);
    Mutex::Autolock lock(mMutex);
    IGraphicBufferProducer::QueueBufferOutput output;
    IGraphicBufferProducer::QueueBufferOutput output;
    mReportRemovedBuffers = reportBufferRemoval;
    mReportRemovedBuffers = reportBufferRemoval;

    if (listener != nullptr) {
    if (listener != nullptr) {
        mListenerProxy = new ProducerListenerProxy(this, listener);
        mListenerProxy = new ProducerListenerProxy(this, listener);
    }
    }
@@ -2053,6 +2079,13 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu
        }
        }


        mConsumerRunningBehind = (output.numPendingBuffers >= 2);
        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) {
    if (!err && api == NATIVE_WINDOW_API_CPU) {
        mConnectedToCpu = true;
        mConnectedToCpu = true;
@@ -2093,6 +2126,14 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) {
            mConnectedToCpu = false;
            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;
    return err;
}
}


+32 −0
Original line number Original line Diff line number Diff line
@@ -66,6 +66,16 @@ public:
    virtual void onBufferAttached() {}
    virtual void onBufferAttached() {}
    virtual bool needsAttachNotify() { return false; }
    virtual bool needsAttachNotify() { return false; }
#endif
#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 {
class StubSurfaceListener : public SurfaceListener {
@@ -471,6 +481,21 @@ protected:
        sp<SurfaceListener> mSurfaceListener;
        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 querySupportedTimestampsLocked() const;


    void freeAllBuffers();
    void freeAllBuffers();
@@ -502,6 +527,13 @@ protected:
    // TODO: rename to mBufferProducer
    // TODO: rename to mBufferProducer
    sp<IGraphicBufferProducer> mGraphicBufferProducer;
    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.
    // 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
    // It is initialized to null pointers, and gets filled in with the result of
    // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a
    // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a
+48 −0
Original line number Original line Diff line number Diff line
@@ -50,7 +50,10 @@
#include <utils/Errors.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/String8.h>


#include <chrono>
#include <cstddef>
#include <cstddef>
#include <cstdint>
#include <future>
#include <limits>
#include <limits>
#include <thread>
#include <thread>


@@ -108,6 +111,18 @@ private:
    std::vector<sp<GraphicBuffer>> mDiscardedBuffers;
    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 {
class SurfaceTest : public ::testing::Test {
protected:
protected:
    SurfaceTest() {
    SurfaceTest() {
@@ -2374,6 +2389,39 @@ TEST_F(SurfaceTest, ViewSurface_toString) {
    surface.name = String16("name");
    surface.name = String16("name");
    EXPECT_EQ("name", surface.toString());
    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)
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)


} // namespace android
} // namespace android