Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5afb7403 authored by Jiwen 'Steve' Cai's avatar Jiwen 'Steve' Cai
Browse files

Update BufferHubQueueProducer

This is the second step to make BufferHub parcelable. There will be one
last CL actually use the parcelable BufferHubQueueProducer in
android::Surface and android::view::Surface to wrap thigns up.

1/ Remove BufferHubQueueProducer::Create(), as there is no real use case
for that at all.
2/ Add support for taking out underlying dvr::ProducerQueueParcelable
with proper safety check.
3/ Update tests to cover the end-to-end case of sending BufferHub-backed
IGBP over binder.

Bug: 37517761
Bug: 63909629
Test: buffer_hub_queue_producer-test
Change-Id: I06ca04b6a8ac1fb15d61ce7884990c3aca1c29ed
parent 4c900d49
Loading
Loading
Loading
Loading
+53 −10
Original line number Diff line number Diff line
@@ -8,16 +8,6 @@
namespace android {
namespace dvr {

/* static */
sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() {
  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
  auto config = ProducerQueueConfigBuilder()
                    .SetMetadata<DvrNativeBufferMetadata>()
                    .Build();
  producer->queue_ = ProducerQueue::Create(config, UsagePolicy{});
  return producer;
}

/* static */
sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
    const std::shared_ptr<ProducerQueue>& queue) {
@@ -33,6 +23,19 @@ sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
  return producer;
}

/* static */
sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
    ProducerQueueParcelable parcelable) {
  if (!parcelable.IsValid()) {
    ALOGE("BufferHubQueueProducer::Create: Invalid producer parcelable.");
    return nullptr;
  }

  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
  producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle());
  return producer;
}

status_t BufferHubQueueProducer::requestBuffer(int slot,
                                               sp<GraphicBuffer>* buf) {
  ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot);
@@ -475,6 +478,13 @@ status_t BufferHubQueueProducer::connect(
    return BAD_VALUE;
  }

  if (!queue_->is_connected()) {
    ALOGE(
        "BufferHubQueueProducer::connect: This BufferHubQueueProducer is not "
        "connected to bufferhud. Has it been taken out as a parcelable?");
    return BAD_VALUE;
  }

  switch (api) {
    case NATIVE_WINDOW_API_EGL:
    case NATIVE_WINDOW_API_CPU:
@@ -617,6 +627,39 @@ status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const {
  return NO_ERROR;
}

status_t BufferHubQueueProducer::TakeAsParcelable(
    ProducerQueueParcelable* out_parcelable) {
  if (!out_parcelable || out_parcelable->IsValid())
    return BAD_VALUE;

  if (connected_api_ != kNoConnectedApi) {
    ALOGE(
        "BufferHubQueueProducer::TakeAsParcelable: BufferHubQueueProducer has "
        "connected client. Must disconnect first.");
    return BAD_VALUE;
  }

  if (!queue_->is_connected()) {
    ALOGE(
        "BufferHubQueueProducer::TakeAsParcelable: This BufferHubQueueProducer "
        "is not connected to bufferhud. Has it been taken out as a "
        "parcelable?");
    return BAD_VALUE;
  }

  auto status = queue_->TakeAsParcelable();
  if (!status) {
    ALOGE(
        "BufferHubQueueProducer::TakeAsParcelable: Failed to take out "
        "ProducuerQueueParcelable from the producer queue, error: %s.",
        status.GetErrorMessage().c_str());
    return BAD_VALUE;
  }

  *out_parcelable = status.take();
  return NO_ERROR;
}

status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
                                                uint32_t layer_count,
                                                PixelFormat format,
+2 −1
Original line number Diff line number Diff line
@@ -74,7 +74,8 @@ class BufferHubQueue : public pdx::Client {
    return available_buffers_.size() >= kMaxQueueCapacity;
  }

  explicit operator bool() const { return epoll_fd_.IsValid(); }
  // Returns whether the buffer queue is connected to bufferhubd.
  bool is_connected() const { return !!GetChannel(); }

  int GetBufferId(size_t slot) const {
    return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
+15 −4
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include <gui/IGraphicBufferProducer.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/buffer_hub_queue_parcelable.h>

namespace android {
namespace dvr {
@@ -17,14 +18,16 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer {
  // that.
  static constexpr int kDefaultUndequeuedBuffers = 1;

  // Create a BufferHubQueueProducer instance by creating a new producer queue.
  static sp<BufferHubQueueProducer> Create();

  // Create a BufferHubQueueProducer instance by importing an existing prodcuer
  // Creates a BufferHubQueueProducer instance by importing an existing prodcuer
  // queue.
  static sp<BufferHubQueueProducer> Create(
      const std::shared_ptr<ProducerQueue>& producer);

  // Creates a BufferHubQueueProducer instance by importing an existing prodcuer
  // parcelable. Note that this call takes the ownership of the parcelable
  // object and is guaranteed to succeed if parcelable object is valid.
  static sp<BufferHubQueueProducer> Create(ProducerQueueParcelable parcelable);

  // See |IGraphicBufferProducer::requestBuffer|
  status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;

@@ -115,6 +118,14 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer {
  // See |IGraphicBufferProducer::getConsumerUsage|
  status_t getConsumerUsage(uint64_t* out_usage) const override;

  // Takes out the current producer as a binder parcelable object. Note that the
  // producer must be disconnected to be exportable. After successful export,
  // the producer queue can no longer be connected again. Returns NO_ERROR when
  // takeout is successful and out_parcelable will hold the new parcelable
  // object. Also note that out_parcelable cannot be NULL and must points to an
  // invalid parcelable.
  status_t TakeAsParcelable(ProducerQueueParcelable* out_parcelable);

 private:
  using LocalHandle = pdx::LocalHandle;

+59 −1
Original line number Diff line number Diff line
@@ -3,12 +3,15 @@
#include <base/logging.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
#include <pdx/default_transport/channel_parcelable.h>

#include <gtest/gtest.h>

namespace android {
namespace dvr {

using pdx::LocalHandle;

namespace {

// Default dimensions before setDefaultBufferSize is called by the consumer.
@@ -92,7 +95,13 @@ class BufferHubQueueProducerTest : public ::testing::Test {
    ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(),
             testInfo->name());

    mProducer = BufferHubQueueProducer::Create();
    auto config = ProducerQueueConfigBuilder()
                      .SetMetadata<DvrNativeBufferMetadata>()
                      .Build();
    auto queue = ProducerQueue::Create(config, UsagePolicy{});
    ASSERT_TRUE(queue != nullptr);

    mProducer = BufferHubQueueProducer::Create(std::move(queue));
    ASSERT_TRUE(mProducer != nullptr);
    mSurface = new Surface(mProducer, true);
    ASSERT_TRUE(mSurface != nullptr);
@@ -546,6 +555,55 @@ TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) {
  EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
}

TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) {
  // Connected producer cannot be taken out as a parcelable.
  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
  ProducerQueueParcelable producer_parcelable;
  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE);

  // Create a valid dummy producer parcelable.
  auto dummy_channel_parcelable =
      std::make_unique<pdx::default_transport::ChannelParcelable>(
          LocalHandle(0), LocalHandle(0), LocalHandle(0));
  EXPECT_TRUE(dummy_channel_parcelable->IsValid());
  ProducerQueueParcelable dummy_producer_parcelable(
      std::move(dummy_channel_parcelable));
  EXPECT_TRUE(dummy_producer_parcelable.IsValid());

  // Disconnect producer can be taken out, but only to an invalid parcelable.
  ASSERT_EQ(mProducer->disconnect(kTestApi), NO_ERROR);
  EXPECT_EQ(mProducer->TakeAsParcelable(&dummy_producer_parcelable), BAD_VALUE);
  EXPECT_FALSE(producer_parcelable.IsValid());
  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), NO_ERROR);
  EXPECT_TRUE(producer_parcelable.IsValid());

  // Should still be able to query buffer dimension after disconnect.
  int32_t value = -1;
  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth);

  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), NO_ERROR);
  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight);

  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), NO_ERROR);
  EXPECT_EQ(value, kDefaultFormat);

  // But connect to API will fail.
  IGraphicBufferProducer::QueueBufferOutput output;
  EXPECT_EQ(mProducer->connect(kDummyListener, kTestApi, kTestControlledByApp,
                               &output),
            BAD_VALUE);

  // Create a new producer from the parcelable and connect to kTestApi should
  // succeed.
  sp<BufferHubQueueProducer> new_producer =
      BufferHubQueueProducer::Create(std::move(producer_parcelable));
  ASSERT_TRUE(new_producer != nullptr);
  EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi,
                                  kTestControlledByApp, &output),
            NO_ERROR);
}

}  // namespace

}  // namespace dvr