Loading libs/gui/tests/BLASTBufferQueue_test.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -195,6 +195,8 @@ public: mBlastBufferQueueAdapter->setApplyToken(std::move(applyToken)); } void dropBbq() { mBlastBufferQueueAdapter.clear(); } private: sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter; }; Loading Loading @@ -1440,6 +1442,50 @@ TEST_F(BLASTBufferQueueTest, TransformHint) { adapter.waitForCallbacks(); } // Verifies that we don't deadlock if BufferQueueProducer::cancelBuffer is called on a thread // right before the owner of BBQ drops its strong pointer (b/410458641). This test is // non-deterministic and sensitive to timings. The owning BBQ pointer may be dropped before, // during, or after notifyBufferReleased is called. This test could be improved by mocking // the BufferReleaseReader, forcing it to wait until after we drop the BBQ pointer. Doing so // would require injecting a mock BufferReleaseReader into BBQ which is difficult to do with the // current code structure. TEST_F(BLASTBufferQueueTest, CancelBuffer_NoDeadlock) { for (int i = 0; i < 100; i++) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> producer; setUpProducer(adapter, producer); int slot; sp<Fence> fence; sp<GraphicBuffer> buf; status_t status = producer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, status); ASSERT_EQ(OK, producer->requestBuffer(slot, &buf)); bool threadComplete = false; std::mutex threadCompleteMutex; std::condition_variable threadCompleteCondition; std::thread thread([&]() { producer->cancelBuffer(slot, fence); std::lock_guard lock{threadCompleteMutex}; threadComplete = true; threadCompleteCondition.notify_one(); }); // Give the background thread some time to start up before dropping the BBQ pointer. std::this_thread::sleep_for(1ms); adapter.dropBbq(); std::unique_lock lock{threadCompleteMutex}; ASSERT_TRUE(threadCompleteCondition.wait_for(lock, 5s, [&]() { return threadComplete; })) << "Failed to join background thread, likely indicates deadlock"; thread.join(); } } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { Loading Loading
libs/gui/tests/BLASTBufferQueue_test.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -195,6 +195,8 @@ public: mBlastBufferQueueAdapter->setApplyToken(std::move(applyToken)); } void dropBbq() { mBlastBufferQueueAdapter.clear(); } private: sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter; }; Loading Loading @@ -1440,6 +1442,50 @@ TEST_F(BLASTBufferQueueTest, TransformHint) { adapter.waitForCallbacks(); } // Verifies that we don't deadlock if BufferQueueProducer::cancelBuffer is called on a thread // right before the owner of BBQ drops its strong pointer (b/410458641). This test is // non-deterministic and sensitive to timings. The owning BBQ pointer may be dropped before, // during, or after notifyBufferReleased is called. This test could be improved by mocking // the BufferReleaseReader, forcing it to wait until after we drop the BBQ pointer. Doing so // would require injecting a mock BufferReleaseReader into BBQ which is difficult to do with the // current code structure. TEST_F(BLASTBufferQueueTest, CancelBuffer_NoDeadlock) { for (int i = 0; i < 100; i++) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> producer; setUpProducer(adapter, producer); int slot; sp<Fence> fence; sp<GraphicBuffer> buf; status_t status = producer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, status); ASSERT_EQ(OK, producer->requestBuffer(slot, &buf)); bool threadComplete = false; std::mutex threadCompleteMutex; std::condition_variable threadCompleteCondition; std::thread thread([&]() { producer->cancelBuffer(slot, fence); std::lock_guard lock{threadCompleteMutex}; threadComplete = true; threadCompleteCondition.notify_one(); }); // Give the background thread some time to start up before dropping the BBQ pointer. std::this_thread::sleep_for(1ms); adapter.dropBbq(); std::unique_lock lock{threadCompleteMutex}; ASSERT_TRUE(threadCompleteCondition.wait_for(lock, 5s, [&]() { return threadComplete; })) << "Failed to join background thread, likely indicates deadlock"; thread.join(); } } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { Loading