libgui: fix an EGLImage leak

This moves the call to ConsumerBase::abandon from the ConsumerBase dtor to
ConsumerBase::onLastStrongRef.  The abandon call relies on virtual methods to
perform the clean-up, so calling it from the ConsumerBase dtor after the
derived classes dtors ran was skipping some of the clean-up.  The
onLastStrongRef method should get called just before the most derived class's
dtor gets called.

Bug: 8349135
Change-Id: I836946826927cc1ed69c049049f525f92b17a269
This commit is contained in:
Jamie Gennis 2013-04-05 16:41:27 -07:00
parent 83a3ad4d57
commit ad669b04f4
3 changed files with 28 additions and 5 deletions

View File

@ -89,6 +89,18 @@ protected:
// buffers from the given BufferQueue.
ConsumerBase(const sp<BufferQueue> &bufferQueue);
// onLastStrongRef gets called by RefBase just before the dtor of the most
// derived class. It is used to clean up the buffers so that ConsumerBase
// can coordinate the clean-up by calling into virtual methods implemented
// by the derived classes. This would not be possible from the
// ConsuemrBase dtor because by the time that gets called the derived
// classes have already been destructed.
//
// This methods should not need to be overridden by derived classes, but
// if they are overridden the ConsumerBase implementation must be called
// from the derived class.
virtual void onLastStrongRef(const void* id);
// Implementation of the BufferQueue::ConsumerListener interface. These
// calls are used to notify the ConsumerBase of asynchronous events in the
// BufferQueue. These methods should not need to be overridden by derived

View File

@ -76,7 +76,18 @@ ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
}
ConsumerBase::~ConsumerBase() {
CB_LOGV("~ConsumerBase");
CB_LOGV("~ConsumerBase");
Mutex::Autolock lock(mMutex);
// Verify that abandon() has been called before we get here. This should
// be done by ConsumerBase::onLastStrongRef(), but it's possible for a
// derived class to override that method and not call
// ConsumerBase::onLastStrongRef().
LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the "
"consumer is not abandoned!", mName.string());
}
void ConsumerBase::onLastStrongRef(const void* id) {
abandon();
}

View File

@ -178,21 +178,21 @@ TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) {
EXPECT_EQ(EGL_SUCCESS, eglGetError());
EGLBoolean success = eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext);
EXPECT_EQ(EGL_TRUE, success);
EXPECT_TRUE(success);
glClear(GL_COLOR_BUFFER_BIT);
success = eglSwapBuffers(mEglDisplay, eglSurface);
EXPECT_EQ(EGL_TRUE, success);
EXPECT_TRUE(success);
mST->abandon();
glClear(GL_COLOR_BUFFER_BIT);
success = eglSwapBuffers(mEglDisplay, eglSurface);
EXPECT_EQ(EGL_FALSE, success);
EXPECT_FALSE(success);
EXPECT_EQ(EGL_BAD_SURFACE, eglGetError());
success = eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
ASSERT_EQ(EGL_TRUE, success);
ASSERT_TRUE(success);
if (eglSurface != EGL_NO_SURFACE) {
eglDestroySurface(mEglDisplay, eglSurface);