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

Commit dda45594 authored by Jiwen 'Steve' Cai's avatar Jiwen 'Steve' Cai Committed by android-build-merger
Browse files

Merge "bufferhubd: Implement more DetachedBuffer logic" into pi-dev

am: c650f621

Change-Id: I9796b0d8960f60c0c3d80a8803f2a46ab2f065cc
parents d4804ff4 c650f621
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
sourceFiles = [
    "buffer_hub_client.cpp",
    "buffer_hub_rpc.cpp",
    "detached_buffer.cpp",
    "ion_buffer.cpp",
]

@@ -59,6 +60,11 @@ cc_library {
    vndk: {
        enabled: true,
    },
    target: {
        vendor: {
            exclude_srcs: ["detached_buffer.cpp"],
        },
    },
}

cc_test {
+87 −2
Original line number Diff line number Diff line
@@ -2,8 +2,10 @@
#include <poll.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/detached_buffer.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <ui/DetachedBufferHandle.h>

#include <mutex>
#include <thread>
@@ -17,22 +19,28 @@
    return result;                            \
  })()

using android::sp;
using android::GraphicBuffer;
using android::dvr::BufferConsumer;
using android::dvr::BufferHubDefs::kConsumerStateMask;
using android::dvr::BufferHubDefs::kMetadataHeaderSize;
using android::dvr::BufferHubDefs::kProducerStateBit;
using android::dvr::BufferHubDefs::IsBufferGained;
using android::dvr::BufferHubDefs::IsBufferPosted;
using android::dvr::BufferHubDefs::IsBufferAcquired;
using android::dvr::BufferHubDefs::IsBufferReleased;
using android::dvr::BufferProducer;
using android::dvr::DetachedBuffer;
using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Status;

const int kWidth = 640;
const int kHeight = 480;
const int kLayerCount = 1;
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
const uint64_t kContext = 42;
const size_t kMaxConsumerCount = 63;
const int kPollTimeoutMs = 100;
@@ -730,6 +738,7 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {

  DvrNativeBufferMetadata metadata;
  LocalHandle invalid_fence;
  int p_id = p->id();

  // Detach in posted state should fail.
  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
@@ -753,8 +762,8 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
  s1 = p->Detach();
  EXPECT_TRUE(s1);

  LocalChannelHandle detached_buffer = s1.take();
  EXPECT_TRUE(detached_buffer.valid());
  LocalChannelHandle handle = s1.take();
  EXPECT_TRUE(handle.valid());

  // Both producer and consumer should have hangup.
  EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
@@ -779,4 +788,80 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
  // ConsumerChannel::HandleMessage as the socket is still open but the producer
  // is gone.
  EXPECT_EQ(s3.error(), EPIPE);

  // Detached buffer handle can be use to construct a new DetachedBuffer object.
  auto d = DetachedBuffer::Import(std::move(handle));
  EXPECT_FALSE(handle.valid());
  EXPECT_TRUE(d->IsValid());

  ASSERT_TRUE(d->buffer() != nullptr);
  EXPECT_EQ(d->buffer()->initCheck(), 0);
  EXPECT_EQ(d->id(), p_id);
}

TEST_F(LibBufferHubTest, TestCreateDetachedBufferFails) {
  // Buffer Creation will fail: BLOB format requires height to be 1.
  auto b1 = DetachedBuffer::Create(kWidth, /*height=2*/2, kLayerCount,
                                   /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
                                   kUserMetadataSize);

  EXPECT_FALSE(b1->IsValid());
  EXPECT_TRUE(b1->buffer() == nullptr);

  // Buffer Creation will fail: user metadata size too large.
  auto b2 = DetachedBuffer::Create(
      kWidth, kHeight, kLayerCount, kFormat, kUsage,
      /*user_metadata_size=*/std::numeric_limits<size_t>::max());

  EXPECT_FALSE(b2->IsValid());
  EXPECT_TRUE(b2->buffer() == nullptr);

  // Buffer Creation will fail: user metadata size too large.
  auto b3 = DetachedBuffer::Create(
      kWidth, kHeight, kLayerCount, kFormat, kUsage,
      /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
          kMetadataHeaderSize);

  EXPECT_FALSE(b3->IsValid());
  EXPECT_TRUE(b3->buffer() == nullptr);
}

TEST_F(LibBufferHubTest, TestCreateDetachedBuffer) {
  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
                                   kUsage, kUserMetadataSize);
  int b1_id = b1->id();

  EXPECT_TRUE(b1->IsValid());
  ASSERT_TRUE(b1->buffer() != nullptr);
  EXPECT_NE(b1->id(), 0);
  EXPECT_EQ(b1->buffer()->initCheck(), 0);
  EXPECT_FALSE(b1->buffer()->isDetachedBuffer());

  // Takes a standalone GraphicBuffer which still holds on an
  // PDX::LocalChannelHandle towards BufferHub.
  sp<GraphicBuffer> g1 = b1->TakeGraphicBuffer();
  ASSERT_TRUE(g1 != nullptr);
  EXPECT_TRUE(g1->isDetachedBuffer());

  EXPECT_FALSE(b1->IsValid());
  EXPECT_TRUE(b1->buffer() == nullptr);

  sp<GraphicBuffer> g2 = b1->TakeGraphicBuffer();
  ASSERT_TRUE(g2 == nullptr);

  auto h1 = g1->takeDetachedBufferHandle();
  ASSERT_TRUE(h1 != nullptr);
  ASSERT_TRUE(h1->isValid());
  EXPECT_FALSE(g1->isDetachedBuffer());

  auto b2 = DetachedBuffer::Import(std::move(h1->handle()));
  ASSERT_FALSE(h1->isValid());
  EXPECT_TRUE(b2->IsValid());

  ASSERT_TRUE(b2->buffer() != nullptr);
  EXPECT_EQ(b2->buffer()->initCheck(), 0);

  // The newly created DetachedBuffer should share the original buffer_id.
  EXPECT_EQ(b2->id(), b1_id);
  EXPECT_FALSE(b2->buffer()->isDetachedBuffer());
}
+20 −0
Original line number Diff line number Diff line
@@ -15,10 +15,30 @@
using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Status;
using android::pdx::default_transport::ClientChannel;
using android::pdx::default_transport::ClientChannelFactory;

namespace android {
namespace dvr {

BufferHubClient::BufferHubClient()
    : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {}

BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle)
    : Client(ClientChannel::Create(std::move(channel_handle))) {}

bool BufferHubClient::IsValid() const {
  return IsConnected() && GetChannelHandle().valid();
}

LocalChannelHandle BufferHubClient::TakeChannelHandle() {
  if (IsConnected()) {
    return std::move(GetChannelHandle());
  } else {
    return {};
  }
}

BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
    : Client{pdx::default_transport::ClientChannel::Create(
          std::move(channel_handle))},
+104 −0
Original line number Diff line number Diff line
#include <private/dvr/detached_buffer.h>

#include <pdx/file_handle.h>
#include <ui/DetachedBufferHandle.h>

using android::pdx::LocalHandle;

namespace android {
namespace dvr {

DetachedBuffer::DetachedBuffer(uint32_t width, uint32_t height,
                               uint32_t layer_count, uint32_t format,
                               uint64_t usage, size_t user_metadata_size) {
  ATRACE_NAME("DetachedBuffer::DetachedBuffer");
  ALOGD_IF(TRACE,
           "DetachedBuffer::DetachedBuffer: width=%u height=%u layer_count=%u, "
           "format=%u usage=%" PRIx64 " user_metadata_size=%zu",
           width, height, layer_count, format, usage, user_metadata_size);

  auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Create>(
      width, height, layer_count, format, usage, user_metadata_size);
  if (!status) {
    ALOGE(
        "DetachedBuffer::DetachedBuffer: Failed to create detached buffer: %s",
        status.GetErrorMessage().c_str());
    client_.Close(-status.error());
  }

  const int ret = ImportGraphicBuffer();
  if (ret < 0) {
    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
          strerror(-ret));
    client_.Close(ret);
  }
}

DetachedBuffer::DetachedBuffer(LocalChannelHandle channel_handle)
    : client_(std::move(channel_handle)) {
  const int ret = ImportGraphicBuffer();
  if (ret < 0) {
    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
          strerror(-ret));
    client_.Close(ret);
  }
}

int DetachedBuffer::ImportGraphicBuffer() {
  ATRACE_NAME("DetachedBuffer::DetachedBuffer");

  auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>();
  if (!status) {
    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import GraphicBuffer: %s",
          status.GetErrorMessage().c_str());
    return -status.error();
  }

  BufferDescription<LocalHandle> buffer_desc = status.take();
  if (buffer_desc.id() < 0) {
    ALOGE("DetachedBuffer::DetachedBuffer: Received an invalid id!");
    return -EIO;
  }

  // Stash the buffer id to replace the value in id_.
  const int buffer_id = buffer_desc.id();

  // Import the buffer.
  IonBuffer ion_buffer;
  ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: id=%d.", buffer_id);

  if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) {
    ALOGE("Failed to import GraphicBuffer, error=%d", ret);
    return ret;
  }

  // If all imports succeed, replace the previous buffer and id.
  id_ = buffer_id;
  buffer_ = std::move(ion_buffer);
  return 0;
}

std::unique_ptr<BufferProducer> DetachedBuffer::Promote() {
  ALOGE("DetachedBuffer::Promote: Not implemented.");
  return nullptr;
}

sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
  if (!client_.IsValid() || !buffer_.buffer()) {
    ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
    return nullptr;
  }

  // Technically this should never happen.
  LOG_FATAL_IF(
      buffer_.buffer()->isDetachedBuffer(),
      "DetachedBuffer::TakeGraphicBuffer: GraphicBuffer is already detached.");

  sp<GraphicBuffer> buffer = std::move(buffer_.buffer());
  buffer->setDetachedBufferHandle(
      DetachedBufferHandle::Create(client_.TakeChannelHandle()));
  return buffer;
}

}  // namespace dvr
}  // namespace android
+15 −0
Original line number Diff line number Diff line
@@ -16,6 +16,21 @@
namespace android {
namespace dvr {

class BufferHubClient : public pdx::Client {
 public:
  using LocalChannelHandle = pdx::LocalChannelHandle;

  BufferHubClient();
  explicit BufferHubClient(LocalChannelHandle channel_handle);

  bool IsValid() const;
  LocalChannelHandle TakeChannelHandle();

  using pdx::Client::Close;
  using pdx::Client::InvokeRemoteMethod;
  using pdx::Client::IsConnected;
};

class BufferHubBuffer : public pdx::Client {
 public:
  using LocalHandle = pdx::LocalHandle;
Loading