From 1a0b8617909c94f6c7301b651cb7b07463529c8c Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Thu, 20 Mar 2014 15:36:31 -0700 Subject: [PATCH] BufferQueue: Test remote producer and consumer Adds a test that puts the BufferQueue into its own process and connects to it over remote binder interfaces. This exposed the fact that while IGBC was technically binderized, it didn't actually work when flattened, so this change also fixes that. Change-Id: I728cdb662a4273ddd3440ed6040a12560313fe68 --- libs/gui/IGraphicBufferConsumer.cpp | 32 ++++++---- libs/gui/tests/BufferQueue_test.cpp | 96 +++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 24 deletions(-) diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 3598a8610..cdd06f315 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -71,11 +71,11 @@ size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const { size_t c = 0; if (mGraphicBuffer != 0) { c += mGraphicBuffer->getFlattenedSize(); - FlattenableUtils::align<4>(c); + c = FlattenableUtils::align<4>(c); } if (mFence != 0) { c += mFence->getFlattenedSize(); - FlattenableUtils::align<4>(c); + c = FlattenableUtils::align<4>(c); } return sizeof(int32_t) + c + getPodSize(); } @@ -91,11 +91,21 @@ size_t IGraphicBufferConsumer::BufferItem::getFdCount() const { return c; } +static void writeBoolAsInt(void*& buffer, size_t& size, bool b) { + FlattenableUtils::write(buffer, size, static_cast(b)); +} + +static bool readBoolFromInt(void const*& buffer, size_t& size) { + int32_t i; + FlattenableUtils::read(buffer, size, i); + return static_cast(i); +} + status_t IGraphicBufferConsumer::BufferItem::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { // make sure we have enough space - if (count < BufferItem::getFlattenedSize()) { + if (size < BufferItem::getFlattenedSize()) { return NO_MEMORY; } @@ -128,12 +138,12 @@ status_t IGraphicBufferConsumer::BufferItem::flatten( FlattenableUtils::write(buffer, size, mTransform); FlattenableUtils::write(buffer, size, mScalingMode); FlattenableUtils::write(buffer, size, mTimestamp); - FlattenableUtils::write(buffer, size, mIsAutoTimestamp); + writeBoolAsInt(buffer, size, mIsAutoTimestamp); FlattenableUtils::write(buffer, size, mFrameNumber); FlattenableUtils::write(buffer, size, mBuf); - FlattenableUtils::write(buffer, size, mIsDroppable); - FlattenableUtils::write(buffer, size, mAcquireCalled); - FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); + writeBoolAsInt(buffer, size, mIsDroppable); + writeBoolAsInt(buffer, size, mAcquireCalled); + writeBoolAsInt(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } @@ -170,12 +180,12 @@ status_t IGraphicBufferConsumer::BufferItem::unflatten( FlattenableUtils::read(buffer, size, mTransform); FlattenableUtils::read(buffer, size, mScalingMode); FlattenableUtils::read(buffer, size, mTimestamp); - FlattenableUtils::read(buffer, size, mIsAutoTimestamp); + mIsAutoTimestamp = readBoolFromInt(buffer, size); FlattenableUtils::read(buffer, size, mFrameNumber); FlattenableUtils::read(buffer, size, mBuf); - FlattenableUtils::read(buffer, size, mIsDroppable); - FlattenableUtils::read(buffer, size, mAcquireCalled); - FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); + mIsDroppable = readBoolFromInt(buffer, size); + mAcquireCalled = readBoolFromInt(buffer, size); + mTransformToDisplayInverse = readBoolFromInt(buffer, size); return NO_ERROR; } diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 5aa34a575..7943476a6 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -24,7 +24,9 @@ #include +#include #include +#include #include namespace android { @@ -32,20 +34,12 @@ namespace android { class BufferQueueTest : public ::testing::Test { public: - static const String16 PRODUCER_NAME; - static const String16 CONSUMER_NAME; - protected: BufferQueueTest() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); - - BufferQueue::createBufferQueue(&mProducer, &mConsumer); - sp serviceManager = defaultServiceManager(); - serviceManager->addService(PRODUCER_NAME, mProducer.get()); - serviceManager->addService(CONSUMER_NAME, mConsumer.get()); } ~BufferQueueTest() { @@ -62,12 +56,13 @@ protected: ASSERT_GE(*bufferCount, 0); } - sp mProducer; - sp mConsumer; -}; + void createBufferQueue() { + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + } -const String16 BufferQueueTest::PRODUCER_NAME = String16("BQTestProducer"); -const String16 BufferQueueTest::CONSUMER_NAME = String16("BQTestConsumer"); + sp mProducer; + sp mConsumer; +}; struct DummyConsumer : public BnConsumerListener { virtual void onFrameAvailable() {} @@ -75,7 +70,74 @@ struct DummyConsumer : public BnConsumerListener { virtual void onSidebandStreamChanged() {} }; +// XXX: Tests that fork a process to hold the BufferQueue must run before tests +// that use a local BufferQueue, or else Binder will get unhappy +TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { + const String16 PRODUCER_NAME = String16("BQTestProducer"); + const String16 CONSUMER_NAME = String16("BQTestConsumer"); + + pid_t forkPid = fork(); + ASSERT_NE(forkPid, -1); + + if (forkPid == 0) { + // Child process + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp serviceManager = defaultServiceManager(); + serviceManager->addService(PRODUCER_NAME, producer.get()); + serviceManager->addService(CONSUMER_NAME, consumer.get()); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + LOG_ALWAYS_FATAL("Shouldn't be here"); + } + + sp serviceManager = defaultServiceManager(); + sp binderProducer = + serviceManager->getService(PRODUCER_NAME); + mProducer = interface_cast(binderProducer); + EXPECT_TRUE(mProducer != NULL); + sp binderConsumer = + serviceManager->getService(CONSUMER_NAME); + mConsumer = interface_cast(binderConsumer); + EXPECT_TRUE(mConsumer != NULL); + + sp dc(new DummyConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, + mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output)); + + int slot; + sp fence; + sp buffer; + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + GRALLOC_USAGE_SW_WRITE_OFTEN)); + ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); + + uint32_t* dataIn; + ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&dataIn))); + *dataIn = 0x12345678; + ASSERT_EQ(OK, buffer->unlock()); + + IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); + ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); + + IGraphicBufferConsumer::BufferItem item; + ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); + + uint32_t* dataOut; + ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, + reinterpret_cast(&dataOut))); + ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); +} + TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { + createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); IGraphicBufferProducer::QueueBufferOutput qbo; @@ -109,6 +171,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { } TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) { + createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); @@ -125,6 +188,7 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) } TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { + createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); @@ -139,6 +203,7 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { } TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { + createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; @@ -187,9 +252,11 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { + createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; @@ -243,9 +310,11 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(OK, buffer->unlock()); } TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { + createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; @@ -283,6 +352,7 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } } // namespace android