From 365857df8b94c959dea984a63013f6e7730ef976 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 11 Sep 2013 19:35:45 -0700 Subject: Make sure do disconnect from a BQ when its client dies. Bug: 5679534 Change-Id: If447e8673df83fe0b1d6210641e0a48522501a53 --- libs/gui/BufferQueue.cpp | 32 +++++++++++++++++++++++++++++--- libs/gui/IGraphicBufferProducer.cpp | 8 +++++--- libs/gui/Surface.cpp | 4 +++- 3 files changed, 37 insertions(+), 7 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 57a41f2..50e3079 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -635,7 +635,9 @@ void BufferQueue::cancelBuffer(int buf, const sp& fence) { mDequeueCondition.broadcast(); } -status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { + +status_t BufferQueue::connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output) { ATRACE_CALL(); ST_LOGV("connect: api=%d producerControlledByApp=%s", api, producerControlledByApp ? "true" : "false"); @@ -663,8 +665,14 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer err = -EINVAL; } else { mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); + output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); + + // set-up a death notification so that we can disconnect automatically + // when/if the remote producer dies. + // This will fail with INVALID_OPERATION if the "token" is local to our process. + if (token->linkToDeath(static_cast(this)) == NO_ERROR) { + mConnectedProducerToken = token; + } } break; default: @@ -678,6 +686,16 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer return err; } +void BufferQueue::binderDied(const wp& who) { + // If we're here, it means that a producer we were connected to died. + // We're GUARANTEED that we still are connected to it because it has no other way + // to get disconnected -- or -- we wouldn't be here because we're removing this + // callback upon disconnect. Therefore, it's okay to read mConnectedApi without + // synchronization here. + int api = mConnectedApi; + this->disconnect(api); +} + status_t BufferQueue::disconnect(int api) { ATRACE_CALL(); ST_LOGV("disconnect: api=%d", api); @@ -701,6 +719,14 @@ status_t BufferQueue::disconnect(int api) { case NATIVE_WINDOW_API_CAMERA: if (mConnectedApi == api) { freeAllBuffersLocked(); + // remove our death notification callback if we have one + sp token = mConnectedProducerToken; + if (token != NULL) { + // this can fail if we're here because of the death notification + // either way, we just ignore. + token->unlinkToDeath(static_cast(this)); + } + mConnectedProducerToken = NULL; mConnectedApi = NO_CONNECTED_API; mDequeueCondition.broadcast(); listener = mConsumerListener; diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 3080220..fc86e60 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -41,7 +41,6 @@ enum { DISCONNECT, }; - class BpGraphicBufferProducer : public BpInterface { public: @@ -139,9 +138,11 @@ public: return result; } - virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { + virtual status_t connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeStrongBinder(token); data.writeInt32(api); data.writeInt32(producerControlledByApp); status_t result = remote()->transact(CONNECT, data, &reply); @@ -241,12 +242,13 @@ status_t BnGraphicBufferProducer::onTransact( } break; case CONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + sp token = data.readStrongBinder(); int api = data.readInt32(); bool producerControlledByApp = data.readInt32(); QueueBufferOutput* const output = reinterpret_cast( reply->writeInplace(sizeof(QueueBufferOutput))); - status_t res = connect(api, producerControlledByApp, output); + status_t res = connect(token, api, producerControlledByApp, output); reply->writeInt32(res); return NO_ERROR; } break; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 1bae0fe..27dbc4e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -490,9 +490,10 @@ int Surface::dispatchUnlockAndPost(va_list args) { int Surface::connect(int api) { ATRACE_CALL(); ALOGV("Surface::connect"); + static sp sLife = new BBinder(); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; - int err = mGraphicBufferProducer->connect(api, mProducerControlledByApp, &output); + int err = mGraphicBufferProducer->connect(sLife, api, mProducerControlledByApp, &output); if (err == NO_ERROR) { uint32_t numPendingBuffers = 0; output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, @@ -505,6 +506,7 @@ int Surface::connect(int api) { return err; } + int Surface::disconnect(int api) { ATRACE_CALL(); ALOGV("Surface::disconnect"); -- cgit v1.1