diff options
author | Dan Stoza <stoza@google.com> | 2015-06-02 15:45:22 -0700 |
---|---|---|
committer | Dan Stoza <stoza@google.com> | 2015-06-03 11:09:33 -0700 |
commit | 812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2 (patch) | |
tree | ceb7515f9f4ded20808bdb322eb9af77366d0629 /libs | |
parent | a8c2454d52d3c23bd53b4a172eff8e5f4af30168 (diff) | |
download | frameworks_native-812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2.zip frameworks_native-812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2.tar.gz frameworks_native-812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2.tar.bz2 |
libgui: Add generation numbers to BufferQueue
This change allows producers to set a generation number on a
BufferQueue. This number will be embedded in any new GraphicBuffers
created in that BufferQueue, and attempts to attach buffers which have
a different generation number will fail.
It also plumbs the setGenerationNumber method through Surface, with the
additional effect that any buffers attached to the Surface after
setting a new generation number will automatically be updated with the
new number (as opposed to failing, as would happen on through IGBP).
Bug: 20923096
Change-Id: I32bf726b035f99c3e5834beaf76afb9f01adcbc2
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/BufferQueueConsumer.cpp | 7 | ||||
-rw-r--r-- | libs/gui/BufferQueueCore.cpp | 3 | ||||
-rw-r--r-- | libs/gui/BufferQueueProducer.cpp | 17 | ||||
-rw-r--r-- | libs/gui/IGraphicBufferProducer.cpp | 19 | ||||
-rw-r--r-- | libs/gui/Surface.cpp | 14 | ||||
-rw-r--r-- | libs/gui/tests/BufferQueue_test.cpp | 42 | ||||
-rw-r--r-- | libs/gui/tests/Surface_test.cpp | 33 | ||||
-rw-r--r-- | libs/ui/GraphicBuffer.cpp | 25 |
8 files changed, 147 insertions, 13 deletions
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 4174676..ae796b1 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -248,6 +248,13 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, return INVALID_OPERATION; } + if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { + BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " + "[queue %u]", buffer->getGenerationNumber(), + mCore->mGenerationNumber); + return BAD_VALUE; + } + // Find a free slot to put the buffer into int found = BufferQueueCore::INVALID_BUFFER_SLOT; if (!mCore->mFreeSlots.empty()) { diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index e784644..851a396 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -71,7 +71,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mIsAllocating(false), mIsAllocatingCondition(), mAllowAllocation(true), - mBufferAge(0) + mBufferAge(0), + mGenerationNumber(0) { if (allocator == NULL) { sp<ISurfaceComposer> composer(ComposerService::getComposerService()); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index e318484..73d4261 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -383,6 +383,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, return NO_INIT; } + graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } // Autolock scope } @@ -498,6 +499,13 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); + if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { + BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " + "[queue %u]", buffer->getGenerationNumber(), + mCore->mGenerationNumber); + return BAD_VALUE; + } + status_t returnFlags = NO_ERROR; int found; // TODO: Should we provide an async flag to attachBuffer? It seems @@ -1072,6 +1080,15 @@ status_t BufferQueueProducer::allowAllocation(bool allow) { return NO_ERROR; } +status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) { + ATRACE_CALL(); + BQ_LOGV("setGenerationNumber: %u", generationNumber); + + Mutex::Autolock lock(mCore->mMutex); + mCore->mGenerationNumber = generationNumber; + return NO_ERROR; +} + void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) { // If we're here, it means that a producer we were connected to died. // We're guaranteed that we are still connected to it because we remove diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 7093ffa..cfe726b 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -47,6 +47,7 @@ enum { SET_SIDEBAND_STREAM, ALLOCATE_BUFFERS, ALLOW_ALLOCATION, + SET_GENERATION_NUMBER, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -284,6 +285,17 @@ public: result = reply.readInt32(); return result; } + + virtual status_t setGenerationNumber(uint32_t generationNumber) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeUint32(generationNumber); + status_t result = remote()->transact(SET_GENERATION_NUMBER, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -448,6 +460,13 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case SET_GENERATION_NUMBER: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + uint32_t generationNumber = data.readUint32(); + status_t result = setGenerationNumber(generationNumber); + reply->writeInt32(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 04ac0f4..aeb56e0 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -42,7 +42,8 @@ namespace android { Surface::Surface( const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) - : mGraphicBufferProducer(bufferProducer) + : mGraphicBufferProducer(bufferProducer), + mGenerationNumber(0) { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; @@ -102,6 +103,14 @@ void Surface::allocateBuffers() { reqHeight, mReqFormat, mReqUsage); } +status_t Surface::setGenerationNumber(uint32_t generation) { + status_t result = mGraphicBufferProducer->setGenerationNumber(generation); + if (result == NO_ERROR) { + mGenerationNumber = generation; + } + return result; +} + int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { Surface* c = getSelf(window); return c->setSwapInterval(interval); @@ -698,11 +707,14 @@ int Surface::attachBuffer(ANativeWindowBuffer* buffer) Mutex::Autolock lock(mMutex); sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer)); + uint32_t priorGeneration = graphicBuffer->mGenerationNumber; + graphicBuffer->mGenerationNumber = mGenerationNumber; int32_t attachedSlot = -1; status_t result = mGraphicBufferProducer->attachBuffer( &attachedSlot, graphicBuffer); if (result != NO_ERROR) { ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result); + graphicBuffer->mGenerationNumber = priorGeneration; return result; } mSlots[attachedSlot].buffer = graphicBuffer; diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 1584fef..3d1139d 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -402,4 +402,46 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); } +TEST_F(BufferQueueTest, TestGenerationNumbers) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + NATIVE_WINDOW_API_CPU, true, &output)); + + ASSERT_EQ(OK, mProducer->setGenerationNumber(1)); + + // Get one buffer to play with + int slot; + sp<Fence> fence; + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, 0)); + + sp<GraphicBuffer> buffer; + ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); + + // Ensure that the generation number we set propagates to allocated buffers + ASSERT_EQ(1U, buffer->getGenerationNumber()); + + ASSERT_EQ(OK, mProducer->detachBuffer(slot)); + + ASSERT_EQ(OK, mProducer->setGenerationNumber(2)); + + // These should fail, since we've changed the generation number on the queue + int outSlot; + ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&outSlot, buffer)); + ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&outSlot, buffer)); + + buffer->setGenerationNumber(2); + + // This should succeed now that we've changed the buffer's generation number + ASSERT_EQ(OK, mProducer->attachBuffer(&outSlot, buffer)); + + ASSERT_EQ(OK, mProducer->detachBuffer(outSlot)); + + // This should also succeed with the new generation number + ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer)); +} + } // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 4f87824..cf0043d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -177,4 +177,37 @@ TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) { ASSERT_EQ(TEST_DATASPACE, dataSpace); } +TEST_F(SurfaceTest, SettingGenerationNumber) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + + // Allocate a buffer with a generation number of 0 + ANativeWindowBuffer* buffer; + int fenceFd; + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd)); + + // Detach the buffer and check its generation number + sp<GraphicBuffer> graphicBuffer; + sp<Fence> fence; + ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&graphicBuffer, &fence)); + ASSERT_EQ(0U, graphicBuffer->getGenerationNumber()); + + ASSERT_EQ(NO_ERROR, surface->setGenerationNumber(1)); + buffer = static_cast<ANativeWindowBuffer*>(graphicBuffer.get()); + + // This should change the generation number of the GraphicBuffer + ASSERT_EQ(NO_ERROR, surface->attachBuffer(buffer)); + + // Check that the new generation number sticks with the buffer + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, -1)); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); + graphicBuffer = static_cast<GraphicBuffer*>(buffer); + ASSERT_EQ(1U, graphicBuffer->getGenerationNumber()); +} + } diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 6a42a22..e55db30 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -278,7 +278,7 @@ status_t GraphicBuffer::unlockAsync(int *fenceFd) } size_t GraphicBuffer::getFlattenedSize() const { - return static_cast<size_t>(10 + (handle ? handle->numInts : 0)) * sizeof(int); + return static_cast<size_t>(11 + (handle ? handle->numInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { @@ -301,15 +301,16 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& buf[5] = usage; buf[6] = static_cast<int32_t>(mId >> 32); buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull); - buf[8] = 0; + buf[8] = static_cast<int32_t>(mGenerationNumber); buf[9] = 0; + buf[10] = 0; if (handle) { - buf[8] = handle->numFds; - buf[9] = handle->numInts; + buf[9] = handle->numFds; + buf[10] = handle->numInts; memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int)); - memcpy(&buf[10], handle->data + handle->numFds, + memcpy(&buf[11], handle->data + handle->numFds, static_cast<size_t>(handle->numInts) * sizeof(int)); } @@ -325,20 +326,20 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& status_t GraphicBuffer::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { - if (size < 8*sizeof(int)) return NO_MEMORY; + if (size < 11 * sizeof(int)) return NO_MEMORY; int const* buf = static_cast<int const*>(buffer); if (buf[0] != 'GBFR') return BAD_TYPE; - const size_t numFds = static_cast<size_t>(buf[8]); - const size_t numInts = static_cast<size_t>(buf[9]); + const size_t numFds = static_cast<size_t>(buf[9]); + const size_t numInts = static_cast<size_t>(buf[10]); // Limit the maxNumber to be relatively small. The number of fds or ints // should not come close to this number, and the number itself was simply // chosen to be high enough to not cause issues and low enough to prevent // overflow problems. const size_t maxNumber = 4096; - if (numFds >= maxNumber || numInts >= (maxNumber - 10)) { + if (numFds >= maxNumber || numInts >= (maxNumber - 11)) { width = height = stride = format = usage = 0; handle = NULL; ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", @@ -346,7 +347,7 @@ status_t GraphicBuffer::unflatten( return BAD_VALUE; } - const size_t sizeNeeded = (10 + numInts) * sizeof(int); + const size_t sizeNeeded = (11 + numInts) * sizeof(int); if (size < sizeNeeded) return NO_MEMORY; size_t fdCountNeeded = numFds; @@ -372,7 +373,7 @@ status_t GraphicBuffer::unflatten( return NO_MEMORY; } memcpy(h->data, fds, numFds * sizeof(int)); - memcpy(h->data + numFds, &buf[10], numInts * sizeof(int)); + memcpy(h->data + numFds, &buf[11], numInts * sizeof(int)); handle = h; } else { width = height = stride = format = usage = 0; @@ -382,6 +383,8 @@ status_t GraphicBuffer::unflatten( mId = static_cast<uint64_t>(buf[6]) << 32; mId |= static_cast<uint32_t>(buf[7]); + mGenerationNumber = static_cast<uint32_t>(buf[8]); + mOwner = ownHandle; if (handle != 0) { |