summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorDan Stoza <stoza@google.com>2015-06-02 15:45:22 -0700
committerDan Stoza <stoza@google.com>2015-06-03 11:09:33 -0700
commit812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2 (patch)
treeceb7515f9f4ded20808bdb322eb9af77366d0629 /libs
parenta8c2454d52d3c23bd53b4a172eff8e5f4af30168 (diff)
downloadframeworks_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.cpp7
-rw-r--r--libs/gui/BufferQueueCore.cpp3
-rw-r--r--libs/gui/BufferQueueProducer.cpp17
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp19
-rw-r--r--libs/gui/Surface.cpp14
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp42
-rw-r--r--libs/gui/tests/Surface_test.cpp33
-rw-r--r--libs/ui/GraphicBuffer.cpp25
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) {