1#include <private/dvr/buffer_hub_queue_producer.h> 2 3#include <base/logging.h> 4#include <gui/IProducerListener.h> 5#include <gui/Surface.h> 6 7#include <gtest/gtest.h> 8 9namespace android { 10namespace dvr { 11 12namespace { 13 14// Default dimensions before setDefaultBufferSize is called by the consumer. 15constexpr uint32_t kDefaultWidth = 1; 16constexpr uint32_t kDefaultHeight = 1; 17 18// Default format before setDefaultBufferFormat is called by the consumer. 19constexpr PixelFormat kDefaultFormat = HAL_PIXEL_FORMAT_RGBA_8888; 20constexpr int kDefaultConsumerUsageBits = 0; 21 22// Default transform hint before setTransformHint is called by the consumer. 23constexpr uint32_t kDefaultTransformHint = 0; 24 25constexpr int kTestApi = NATIVE_WINDOW_API_CPU; 26constexpr int kTestApiOther = NATIVE_WINDOW_API_EGL; 27constexpr int kTestApiInvalid = 0xDEADBEEF; 28constexpr int kTestProducerUsageBits = 0; 29constexpr bool kTestControlledByApp = true; 30 31// Builder pattern to slightly vary *almost* correct input 32// -- avoids copying and pasting 33struct QueueBufferInputBuilder { 34 IGraphicBufferProducer::QueueBufferInput build() { 35 return IGraphicBufferProducer::QueueBufferInput( 36 mTimestamp, mIsAutoTimestamp, mDataSpace, mCrop, mScalingMode, 37 mTransform, mFence); 38 } 39 40 QueueBufferInputBuilder& setTimestamp(int64_t timestamp) { 41 this->mTimestamp = timestamp; 42 return *this; 43 } 44 45 QueueBufferInputBuilder& setIsAutoTimestamp(bool isAutoTimestamp) { 46 this->mIsAutoTimestamp = isAutoTimestamp; 47 return *this; 48 } 49 50 QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) { 51 this->mDataSpace = dataSpace; 52 return *this; 53 } 54 55 QueueBufferInputBuilder& setCrop(Rect crop) { 56 this->mCrop = crop; 57 return *this; 58 } 59 60 QueueBufferInputBuilder& setScalingMode(int scalingMode) { 61 this->mScalingMode = scalingMode; 62 return *this; 63 } 64 65 QueueBufferInputBuilder& setTransform(uint32_t transform) { 66 this->mTransform = transform; 67 return *this; 68 } 69 70 QueueBufferInputBuilder& setFence(sp<Fence> fence) { 71 this->mFence = fence; 72 return *this; 73 } 74 75 private: 76 int64_t mTimestamp{1384888611}; 77 bool mIsAutoTimestamp{false}; 78 android_dataspace mDataSpace{HAL_DATASPACE_UNKNOWN}; 79 Rect mCrop{Rect(kDefaultWidth, kDefaultHeight)}; 80 int mScalingMode{0}; 81 uint32_t mTransform{0}; 82 sp<Fence> mFence{Fence::NO_FENCE}; 83}; 84 85// This is a test that covers our implementation of bufferhubqueue-based 86// IGraphicBufferProducer. 87class BufferHubQueueProducerTest : public ::testing::Test { 88 protected: 89 virtual void SetUp() { 90 const ::testing::TestInfo* const testInfo = 91 ::testing::UnitTest::GetInstance()->current_test_info(); 92 ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(), 93 testInfo->name()); 94 95 mProducer = BufferHubQueueProducer::Create(); 96 ASSERT_TRUE(mProducer != nullptr); 97 mSurface = new Surface(mProducer, true); 98 ASSERT_TRUE(mSurface != nullptr); 99 } 100 101 // Connect to a producer in a 'correct' fashion. 102 void ConnectProducer() { 103 IGraphicBufferProducer::QueueBufferOutput output; 104 // Can connect the first time. 105 ASSERT_EQ(NO_ERROR, mProducer->connect(kDummyListener, kTestApi, 106 kTestControlledByApp, &output)); 107 } 108 109 // Dequeue a buffer in a 'correct' fashion. 110 // Precondition: Producer is connected. 111 void DequeueBuffer(int* outSlot) { 112 sp<Fence> fence; 113 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(outSlot, &fence)); 114 } 115 116 void DequeueBuffer(int* outSlot, sp<Fence>* outFence) { 117 ASSERT_NE(nullptr, outSlot); 118 ASSERT_NE(nullptr, outFence); 119 120 int ret = mProducer->dequeueBuffer(outSlot, outFence, kDefaultWidth, 121 kDefaultHeight, kDefaultFormat, 122 kTestProducerUsageBits, nullptr); 123 // BUFFER_NEEDS_REALLOCATION can be either on or off. 124 ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret); 125 126 // Slot number should be in boundary. 127 ASSERT_LE(0, *outSlot); 128 ASSERT_GT(BufferQueueDefs::NUM_BUFFER_SLOTS, *outSlot); 129 } 130 131 // Create a generic "valid" input for queueBuffer 132 // -- uses the default buffer format, width, etc. 133 static IGraphicBufferProducer::QueueBufferInput CreateBufferInput() { 134 return QueueBufferInputBuilder().build(); 135 } 136 137 const sp<IProducerListener> kDummyListener{new DummyProducerListener}; 138 139 sp<BufferHubQueueProducer> mProducer; 140 sp<Surface> mSurface; 141}; 142 143TEST_F(BufferHubQueueProducerTest, ConnectFirst_ReturnsError) { 144 IGraphicBufferProducer::QueueBufferOutput output; 145 146 // NULL output returns BAD_VALUE 147 EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi, 148 kTestControlledByApp, nullptr)); 149 150 // Invalid API returns bad value 151 EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApiInvalid, 152 kTestControlledByApp, &output)); 153} 154 155TEST_F(BufferHubQueueProducerTest, ConnectAgain_ReturnsError) { 156 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 157 158 // Can't connect when there is already a producer connected. 159 IGraphicBufferProducer::QueueBufferOutput output; 160 EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi, 161 kTestControlledByApp, &output)); 162} 163 164TEST_F(BufferHubQueueProducerTest, Disconnect_Succeeds) { 165 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 166 167 ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); 168} 169 170TEST_F(BufferHubQueueProducerTest, Disconnect_ReturnsError) { 171 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 172 173 // Must disconnect with same API number 174 EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiOther)); 175 // API must not be out of range 176 EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiInvalid)); 177} 178 179TEST_F(BufferHubQueueProducerTest, Query_Succeeds) { 180 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 181 182 int32_t value = -1; 183 EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value)); 184 EXPECT_EQ(kDefaultWidth, static_cast<uint32_t>(value)); 185 186 EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_HEIGHT, &value)); 187 EXPECT_EQ(kDefaultHeight, static_cast<uint32_t>(value)); 188 189 EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); 190 EXPECT_EQ(kDefaultFormat, value); 191 192 EXPECT_EQ(NO_ERROR, 193 mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value)); 194 EXPECT_LE(0, value); 195 EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, static_cast<size_t>(value)); 196 197 EXPECT_EQ(NO_ERROR, 198 mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value)); 199 EXPECT_FALSE(value); // Can't run behind when we haven't touched the queue 200 201 EXPECT_EQ(NO_ERROR, 202 mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &value)); 203 EXPECT_EQ(kDefaultConsumerUsageBits, value); 204} 205 206TEST_F(BufferHubQueueProducerTest, Query_ReturnsError) { 207 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 208 209 // One past the end of the last 'query' enum value. Update this if we add more 210 // enums. 211 const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1; 212 213 int value; 214 // What was out of range 215 EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ -1, &value)); 216 EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ 0xDEADBEEF, &value)); 217 EXPECT_EQ(BAD_VALUE, 218 mProducer->query(NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE, &value)); 219 220 // Some enums from window.h are 'invalid' 221 EXPECT_EQ(BAD_VALUE, 222 mProducer->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &value)); 223 EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_CONCRETE_TYPE, &value)); 224 EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_WIDTH, &value)); 225 EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_HEIGHT, &value)); 226 EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_TRANSFORM_HINT, &value)); 227 228 // Value was NULL 229 EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/ NULL)); 230} 231 232TEST_F(BufferHubQueueProducerTest, Queue_Succeeds) { 233 int slot = -1; 234 235 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 236 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 237 238 // Request the buffer (pre-requisite for queueing) 239 sp<GraphicBuffer> buffer; 240 ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); 241 242 // A generic "valid" input 243 IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); 244 IGraphicBufferProducer::QueueBufferOutput output; 245 246 // Queue the buffer back into the BQ 247 ASSERT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); 248 249 EXPECT_EQ(kDefaultWidth, output.width); 250 EXPECT_EQ(kDefaultHeight, output.height); 251 EXPECT_EQ(kDefaultTransformHint, output.transformHint); 252 253 // BufferHubQueue delivers buffers to consumer immediately. 254 EXPECT_EQ(0u, output.numPendingBuffers); 255 256 // Note that BufferHubQueue doesn't support nextFrameNumber as it seems to 257 // be a SurfaceFlinger specific optimization. 258 EXPECT_EQ(0u, output.nextFrameNumber); 259 260 // Buffer was not in the dequeued state 261 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); 262} 263 264// Test invalid slot number 265TEST_F(BufferHubQueueProducerTest, QueueInvalidSlot_ReturnsError) { 266 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 267 268 // A generic "valid" input 269 IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); 270 IGraphicBufferProducer::QueueBufferOutput output; 271 272 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ -1, input, &output)); 273 EXPECT_EQ(BAD_VALUE, 274 mProducer->queueBuffer(/*slot*/ 0xDEADBEEF, input, &output)); 275 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(BufferQueueDefs::NUM_BUFFER_SLOTS, 276 input, &output)); 277} 278 279// Slot was not in the dequeued state (all slots start out in Free state) 280TEST_F(BufferHubQueueProducerTest, QueueNotDequeued_ReturnsError) { 281 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 282 283 IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); 284 IGraphicBufferProducer::QueueBufferOutput output; 285 286 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ 0, input, &output)); 287} 288 289// Slot was enqueued without requesting a buffer 290TEST_F(BufferHubQueueProducerTest, QueueNotRequested_ReturnsError) { 291 int slot = -1; 292 293 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 294 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 295 296 IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); 297 IGraphicBufferProducer::QueueBufferOutput output; 298 299 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); 300} 301 302// Test when fence was NULL 303TEST_F(BufferHubQueueProducerTest, QueueNoFence_ReturnsError) { 304 int slot = -1; 305 306 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 307 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 308 309 sp<GraphicBuffer> buffer; 310 ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); 311 312 sp<Fence> nullFence = NULL; 313 314 IGraphicBufferProducer::QueueBufferInput input = 315 QueueBufferInputBuilder().setFence(nullFence).build(); 316 IGraphicBufferProducer::QueueBufferOutput output; 317 318 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); 319} 320 321// Test scaling mode was invalid 322TEST_F(BufferHubQueueProducerTest, QueueTestInvalidScalingMode_ReturnsError) { 323 int slot = -1; 324 325 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 326 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 327 328 sp<GraphicBuffer> buffer; 329 ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); 330 331 IGraphicBufferProducer::QueueBufferInput input = 332 QueueBufferInputBuilder().setScalingMode(-1).build(); 333 IGraphicBufferProducer::QueueBufferOutput output; 334 335 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); 336 337 input = QueueBufferInputBuilder().setScalingMode(0xDEADBEEF).build(); 338 339 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); 340} 341 342// Test crop rect is out of bounds of the buffer dimensions 343TEST_F(BufferHubQueueProducerTest, QueueCropOutOfBounds_ReturnsError) { 344 int slot = -1; 345 346 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 347 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 348 349 sp<GraphicBuffer> buffer; 350 ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); 351 352 IGraphicBufferProducer::QueueBufferInput input = 353 QueueBufferInputBuilder() 354 .setCrop(Rect(kDefaultWidth + 1, kDefaultHeight + 1)) 355 .build(); 356 IGraphicBufferProducer::QueueBufferOutput output; 357 358 EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output)); 359} 360 361TEST_F(BufferHubQueueProducerTest, CancelBuffer_Succeeds) { 362 int slot = -1; 363 sp<Fence> fence; 364 365 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 366 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence)); 367 368 // Should be able to cancel buffer after a dequeue. 369 EXPECT_EQ(NO_ERROR, mProducer->cancelBuffer(slot, fence)); 370} 371 372TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Succeeds) { 373 return; 374 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 375 376 int minUndequeuedBuffers; 377 ASSERT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 378 &minUndequeuedBuffers)); 379 380 const int minBuffers = 1; 381 const int maxBuffers = 382 BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers; 383 384 ASSERT_EQ(NO_ERROR, mProducer->setAsyncMode(false)) 385 << "async mode: " << false; 386 ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(minBuffers)) 387 << "bufferCount: " << minBuffers; 388 389 // Should now be able to dequeue up to minBuffers times 390 // Should now be able to dequeue up to maxBuffers times 391 int slot = -1; 392 for (int i = 0; i < minBuffers; ++i) { 393 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 394 } 395 396 ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxBuffers)); 397 398 // queue the first buffer to enable max dequeued buffer count checking 399 IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); 400 IGraphicBufferProducer::QueueBufferOutput output; 401 sp<GraphicBuffer> buffer; 402 ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); 403 ASSERT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output)); 404 405 sp<Fence> fence; 406 for (int i = 0; i < maxBuffers; ++i) { 407 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence)); 408 } 409 410 // Cancel a buffer, so we can decrease the buffer count 411 ASSERT_EQ(NO_ERROR, mProducer->cancelBuffer(slot, fence)); 412 413 // Should now be able to decrease the max dequeued count by 1 414 ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxBuffers - 1)); 415} 416 417TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Fails) { 418 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 419 420 int minUndequeuedBuffers; 421 ASSERT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 422 &minUndequeuedBuffers)); 423 424 const int minBuffers = 1; 425 const int maxBuffers = 426 BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers; 427 428 ASSERT_EQ(NO_ERROR, mProducer->setAsyncMode(false)) 429 << "async mode: " << false; 430 // Buffer count was out of range 431 EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0)) 432 << "bufferCount: " << 0; 433 EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1)) 434 << "bufferCount: " << maxBuffers + 1; 435 436 // Set max dequeue count to 2 437 ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(2)); 438 // Dequeue 2 buffers 439 int slot = -1; 440 sp<Fence> fence; 441 for (int i = 0; i < 2; i++) { 442 ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & 443 (mProducer->dequeueBuffer( 444 &slot, &fence, kDefaultWidth, kDefaultHeight, 445 kDefaultFormat, kTestProducerUsageBits, nullptr))) 446 << "slot: " << slot; 447 } 448 449 // Client has too many buffers dequeued 450 EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1)) 451 << "bufferCount: " << minBuffers; 452} 453 454TEST_F(BufferHubQueueProducerTest, 455 DisconnectedProducerReturnsError_dequeueBuffer) { 456 int slot = -1; 457 sp<Fence> fence; 458 459 ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth, 460 kDefaultHeight, kDefaultFormat, 461 kTestProducerUsageBits, nullptr)); 462} 463 464TEST_F(BufferHubQueueProducerTest, 465 DisconnectedProducerReturnsError_requestBuffer) { 466 int slot = -1; 467 sp<GraphicBuffer> buffer; 468 469 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 470 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 471 472 // Shouldn't be able to request buffer after disconnect. 473 ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); 474 ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer)); 475} 476 477TEST_F(BufferHubQueueProducerTest, 478 DisconnectedProducerReturnsError_queueBuffer) { 479 int slot = -1; 480 sp<GraphicBuffer> buffer; 481 482 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 483 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 484 ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); 485 486 // A generic "valid" input 487 IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); 488 IGraphicBufferProducer::QueueBufferOutput output; 489 490 // Shouldn't be able to queue buffer after disconnect. 491 ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); 492 ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output)); 493} 494 495TEST_F(BufferHubQueueProducerTest, 496 DisconnectedProducerReturnsError_cancelBuffer) { 497 int slot = -1; 498 sp<GraphicBuffer> buffer; 499 500 ASSERT_NO_FATAL_FAILURE(ConnectProducer()); 501 ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot)); 502 ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer)); 503 504 // Shouldn't be able to cancel buffer after disconnect. 505 ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); 506 ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE)); 507} 508 509} // namespace 510 511} // namespace dvr 512} // namespace android 513