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

Commit 9004b8c9 authored by Jiwen 'Steve' Cai's avatar Jiwen 'Steve' Cai
Browse files

Move detached buffer off IonBuffer

1/ Migration DetachedBuffer's metadata to use ashmem-based
   BufferHubMetadata.
2/ Avoid import the actual gralloc buffer into the IonBuffer. Instead,
   just store the native_handle_t of the gralloc buffer in DetachedBuffer.
3/ Replace the usage of BufferDescription/NativeBufferHandle with
   BufferTraits/NativeHandleWrapper, as they both depend on
   IonBuffer. Currently dvr::ProdcuerBuffer and dvr::ConsumerBuffer
   are still using BufferDescription/NativeBufferHandle so that we are
   reimplementing them for DetachedBuffer to avoid chaning
   dvr::ProdcuerBuffer and dvr::ConsumerBuffer at this point.

Bug: 112940221
Bug: 112011098
Bug: 70048475
Test: atest buffer_hub-test
Change-Id: I435180ba80a27b0ff35f0d95fcdbc23412978e22
parent 995285ab
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -920,6 +920,7 @@ TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
                                   kUsage, kUserMetadataSize);
  int b1_id = b1->id();
  EXPECT_TRUE(b1->IsValid());
  EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);

  auto status_or_handle = b1->Duplicate();
  EXPECT_TRUE(status_or_handle);
@@ -935,6 +936,9 @@ TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
  std::unique_ptr<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
  EXPECT_FALSE(h2.valid());
  ASSERT_TRUE(b2 != nullptr);
  EXPECT_TRUE(b2->IsValid());
  EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);

  int b2_id = b2->id();

  // These two buffer instances are based on the same physical buffer under the
+3 −0
Original line number Diff line number Diff line
@@ -74,6 +74,9 @@ BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmem_handle) {
  size_t metadata_size = ashmem_get_size_region(ashmem_handle.Get());
  size_t user_metadata_size = metadata_size - kMetadataHeaderSize;

  // Note that here the buffer state is mapped from shared memory as an atomic
  // object. The std::atomic's constructor will not be called so that the
  // original value stored in the memory region can be preserved.
  auto metadata_header = static_cast<MetadataHeader*>(
      mmap(nullptr, metadata_size, kAshmemProt, MAP_SHARED, ashmem_handle.Get(),
           /*offset=*/0));
+35 −45
Original line number Diff line number Diff line
@@ -16,8 +16,16 @@ using android::pdx::default_transport::ClientChannelFactory;
namespace android {
namespace dvr {

namespace {

// TODO(b/112338294): Remove this string literal after refactoring BufferHub
// to use Binder.
static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";

}  // namespace

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

BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle)
    : Client(ClientChannel::Create(std::move(channel_handle))) {}
@@ -80,71 +88,53 @@ int DetachedBuffer::ImportGraphicBuffer() {
    return -status.error();
  }

  BufferDescription<LocalHandle> buffer_desc = status.take();
  if (buffer_desc.id() < 0) {
  BufferTraits<LocalHandle> buffer_traits = status.take();
  if (buffer_traits.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();
  const int buffer_id = buffer_traits.id();

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

  if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) {
    ALOGE("Failed to import GraphicBuffer, error=%d", ret);
    return ret;
  if (!metadata_.IsValid()) {
    ALOGE("DetachedBuffer::ImportGraphicBuffer: invalid metadata.");
    return -ENOMEM;
  }

  // Import the metadata.
  IonBuffer metadata_buffer;
  if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
    ALOGE("Failed to import metadata buffer, error=%d", ret);
    return ret;
  if (metadata_.metadata_size() != buffer_traits.metadata_size()) {
    ALOGE(
        "DetachedBuffer::ImportGraphicBuffer: metadata buffer too small: "
        "%zu, expected: %" PRIu64 ".",
        metadata_.metadata_size(), buffer_traits.metadata_size());
    return -ENOMEM;
  }
  size_t metadata_buf_size = metadata_buffer.width();

  size_t metadata_buf_size = buffer_traits.metadata_size();
  if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
    ALOGE("DetachedBuffer::ImportGraphicBuffer: metadata buffer too small: %zu",
    ALOGE("DetachedBuffer::ImportGraphicBuffer: metadata too small: %zu",
          metadata_buf_size);
    return -EINVAL;
  }

  // Import the buffer: We only need to hold on the native_handle_t here so that
  // GraphicBuffer instance can be created in future.
  buffer_handle_ = buffer_traits.take_buffer_handle();

  // If all imports succeed, replace the previous buffer and id.
  id_ = buffer_id;
  buffer_ = std::move(ion_buffer);
  metadata_buffer_ = std::move(metadata_buffer);
  user_metadata_size_ = metadata_buf_size - BufferHubDefs::kMetadataHeaderSize;

  void* metadata_ptr = nullptr;
  if (const int ret =
          metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
                                /*y=*/0, metadata_buf_size,
                                /*height=*/1, &metadata_ptr)) {
    ALOGE("DetachedBuffer::ImportGraphicBuffer: Failed to lock metadata.");
    return ret;
  }
  buffer_state_bit_ = buffer_traits.buffer_state_bit();

  // TODO(b/112012161) Set up shared fences.

  // Note that here the buffer state is mapped from shared memory as an atomic
  // object. The std::atomic's constructor will not be called so that the
  // original value stored in the memory region can be preserved.
  metadata_header_ = static_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
  if (user_metadata_size_) {
    user_metadata_ptr_ = static_cast<void*>(metadata_header_ + 1);
  } else {
    user_metadata_ptr_ = nullptr;
  }

  id_ = buffer_desc.id();
  buffer_state_bit_ = buffer_desc.buffer_state_bit();

  ALOGD_IF(TRACE,
           "DetachedBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64
           ".",
           id(), metadata_header_->buffer_state.load());
           id(),
           metadata_.metadata_header()->buffer_state.load(
               std::memory_order_acquire));
  return 0;
}

@@ -166,7 +156,7 @@ Status<LocalChannelHandle> DetachedBuffer::Promote() {
      client_.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
  if (status_or_handle.ok()) {
    // Invalidate the buffer.
    buffer_ = {};
    buffer_handle_ = {};
  } else {
    ALOGE("DetachedBuffer::Promote: Failed to promote buffer (id=%d): %s.", id_,
          status_or_handle.GetErrorMessage().c_str());
+135 −1
Original line number Diff line number Diff line
@@ -3,6 +3,11 @@

#include <dvr/dvr_api.h>
#include <hardware/gralloc.h>
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/remote_method.h>
#include <pdx/rpc/serializable.h>
#include <private/dvr/native_handle_wrapper.h>

#include <atomic>

@@ -82,8 +87,137 @@ static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);

}  // namespace BufferHubDefs

template <typename FileHandleType>
class BufferTraits {
 public:
  BufferTraits() = default;
  BufferTraits(const native_handle_t* buffer_handle,
               const FileHandleType& metadata_handle, int id,
               uint64_t buffer_state_bit, uint64_t metadata_size,
               uint32_t width, uint32_t height, uint32_t layer_count,
               uint32_t format, uint64_t usage, uint32_t stride,
               const FileHandleType& acquire_fence_fd,
               const FileHandleType& release_fence_fd)
      : id_(id),
        buffer_state_bit_(buffer_state_bit),
        metadata_size_(metadata_size),
        width_(width),
        height_(height),
        layer_count_(layer_count),
        format_(format),
        usage_(usage),
        stride_(stride),
        buffer_handle_(buffer_handle),
        metadata_handle_(metadata_handle.Borrow()),
        acquire_fence_fd_(acquire_fence_fd.Borrow()),
        release_fence_fd_(release_fence_fd.Borrow()) {}

  BufferTraits(BufferTraits&& other) = default;
  BufferTraits& operator=(BufferTraits&& other) = default;

  // ID of the buffer client. All BufferHubBuffer clients derived from the same
  // buffer in bufferhubd share the same buffer id.
  int id() const { return id_; }

  // State mask of the buffer client. Each BufferHubBuffer client backed by the
  // same buffer channel has uniqued state bit among its siblings. For a
  // producer buffer the bit must be kProducerStateBit; for a consumer the bit
  // must be one of the kConsumerStateMask.
  uint64_t buffer_state_bit() const { return buffer_state_bit_; }
  uint64_t metadata_size() const { return metadata_size_; }

  uint32_t width() { return width_; }
  uint32_t height() { return height_; }
  uint32_t layer_count() { return layer_count_; }
  uint32_t format() { return format_; }
  uint64_t usage() { return usage_; }
  uint32_t stride() { return stride_; }

  const NativeHandleWrapper<FileHandleType>& buffer_handle() const {
    return buffer_handle_;
  }

  NativeHandleWrapper<FileHandleType> take_buffer_handle() {
    return std::move(buffer_handle_);
  }
  FileHandleType take_metadata_handle() { return std::move(metadata_handle_); }
  FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
  FileHandleType take_release_fence() { return std::move(release_fence_fd_); }

 private:
  // BufferHub specific traits.
  int id_ = -1;
  uint64_t buffer_state_bit_;
  uint64_t metadata_size_;

  // Traits for a GraphicBuffer.
  uint32_t width_;
  uint32_t height_;
  uint32_t layer_count_;
  uint32_t format_;
  uint64_t usage_;
  uint32_t stride_;

  // Native handle for the graphic buffer.
  NativeHandleWrapper<FileHandleType> buffer_handle_;

  // File handle of an ashmem that holds buffer metadata.
  FileHandleType metadata_handle_;

  // Pamameters for shared fences.
  FileHandleType acquire_fence_fd_;
  FileHandleType release_fence_fd_;

  PDX_SERIALIZABLE_MEMBERS(BufferTraits<FileHandleType>, id_, buffer_state_bit_,
                           metadata_size_, stride_, width_, height_,
                           layer_count_, format_, usage_, buffer_handle_,
                           metadata_handle_, acquire_fence_fd_,
                           release_fence_fd_);

  BufferTraits(const BufferTraits&) = delete;
  void operator=(const BufferTraits&) = delete;
};

struct DetachedBufferRPC {
 private:
  enum {
    kOpDetachedBufferBase = 1000,

    // Allocates a standalone DetachedBuffer not associated with any producer
    // consumer set.
    kOpCreate,

    // Imports the given channel handle to a DetachedBuffer, taking ownership.
    kOpImport,

    // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
    // DetachedBuffer channel will be closed automatically on successful IPC
    // return. Further IPCs towards this channel will return error.
    kOpPromote,

    // Creates a DetachedBuffer client from an existing one. The new client will
    // share the same underlying gralloc buffer and ashmem region for metadata.
    kOpDuplicate,
  };

  // Aliases.
  using LocalChannelHandle = pdx::LocalChannelHandle;
  using LocalHandle = pdx::LocalHandle;
  using Void = pdx::rpc::Void;

 public:
  PDX_REMOTE_METHOD(Create, kOpCreate,
                    void(uint32_t width, uint32_t height, uint32_t layer_count,
                         uint32_t format, uint64_t usage,
                         size_t user_metadata_size));
  PDX_REMOTE_METHOD(Import, kOpImport, BufferTraits<LocalHandle>(Void));
  PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
  PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));

  PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
};

}  // namespace dvr
}  // namespace android


#endif  // ANDROID_DVR_BUFFER_HUB_DEFS_H_
+0 −24
Original line number Diff line number Diff line
@@ -316,8 +316,6 @@ struct BufferHubRPC {
    kOpConsumerRelease,
    kOpProducerBufferDetach,
    kOpConsumerBufferDetach,
    kOpDetachedBufferCreate,
    kOpDetachedBufferPromote,
    kOpCreateProducerQueue,
    kOpCreateConsumerQueue,
    kOpGetQueueInfo,
@@ -326,7 +324,6 @@ struct BufferHubRPC {
    kOpProducerQueueRemoveBuffer,
    kOpConsumerQueueImportBuffers,
    // TODO(b/77153033): Separate all those RPC operations into subclasses.
    kOpDetachedBufferBase = 1000,
  };

  // Aliases.
@@ -379,27 +376,6 @@ struct BufferHubRPC {
                    std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
};

struct DetachedBufferRPC final : public BufferHubRPC {
 private:
  enum {
    kOpCreate = kOpDetachedBufferBase,
    kOpImport,
    kOpPromote,
    kOpDuplicate,
  };

 public:
  PDX_REMOTE_METHOD(Create, kOpCreate,
                    void(uint32_t width, uint32_t height, uint32_t layer_count,
                         uint32_t format, uint64_t usage,
                         size_t user_metadata_size));
  PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void));
  PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
  PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));

  PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
};

}  // namespace dvr
}  // namespace android

Loading