Move core data structure of DetachedBuffer into BufferNode
1/ Supports mutiple DetachedBuffer(s) to be created from a single
BufferNode.
2/ Separate core data structure and logic (i.e. BufferNode) out of the
IPC layer (i.e. DetachedBufferChannel).
3/ DetachedBufferChannel will be renamed to BufferChannel in future
and becomes the universal backend of GraphicBuffer. Thus we are naming
the new class BufferNode instead of DetachedBufferNode.
4/ Move BufferHubDefs out of bufferhub_rpc.h, as BufferHubDefs is not
directly related to the PDX IPCm echanism.
Bug: 112011098
Bug: 112012812
Bug: 111976433
Bug: 70046255
Test: buffer_hub-test
Change-Id: Ieba19329a0e823c78f21611462dedacdad3aab85
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index e247398..2a962b5 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -945,3 +945,35 @@
EXPECT_EQ(b1_id, p2_id);
EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
}
+
+TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
+ auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
+ int b1_id = b1->id();
+ EXPECT_TRUE(b1->IsValid());
+
+ auto status_or_handle = b1->Duplicate();
+ EXPECT_TRUE(status_or_handle);
+
+ // The detached buffer should still be valid.
+ EXPECT_TRUE(b1->IsConnected());
+ EXPECT_TRUE(b1->IsValid());
+
+ // Gets the channel handle for the duplicated buffer.
+ LocalChannelHandle h2 = status_or_handle.take();
+ EXPECT_TRUE(h2.valid());
+
+ std::unique_ptr<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
+ EXPECT_FALSE(h2.valid());
+ ASSERT_TRUE(b2 != nullptr);
+ int b2_id = b2->id();
+
+ // The duplicated buffer should inherit the same buffer id.
+ EXPECT_EQ(b1_id, b2_id);
+
+ // Promote the detached buffer should fail as b1 is no longer the exclusive
+ // owner of the buffer..
+ status_or_handle = b1->Promote();
+ EXPECT_FALSE(status_or_handle.ok());
+ EXPECT_EQ(status_or_handle.error(), EINVAL);
+}
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
index 6fae16d..60f11e2 100644
--- a/libs/vr/libbufferhub/detached_buffer.cpp
+++ b/libs/vr/libbufferhub/detached_buffer.cpp
@@ -104,6 +104,20 @@
return status_or_handle;
}
+Status<LocalChannelHandle> DetachedBuffer::Duplicate() {
+ ATRACE_NAME("DetachedBuffer::Duplicate");
+ ALOGD_IF(TRACE, "DetachedBuffer::Duplicate: id=%d.", id_);
+
+ auto status_or_handle =
+ client_.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
+
+ if (!status_or_handle.ok()) {
+ ALOGE("DetachedBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.",
+ id_, status_or_handle.GetErrorMessage().c_str());
+ }
+ return status_or_handle;
+}
+
sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
if (!client_.IsValid() || !buffer_.buffer()) {
ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
new file mode 100644
index 0000000..8b2bf91
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -0,0 +1,89 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_DEFS_H_
+#define ANDROID_DVR_BUFFER_HUB_DEFS_H_
+
+#include <dvr/dvr_api.h>
+#include <hardware/gralloc.h>
+
+#include <atomic>
+
+namespace android {
+namespace dvr {
+
+namespace BufferHubDefs {
+
+static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint32_t kMetadataUsage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+// Single producuer multiple (up to 63) consumers ownership signal.
+// 64-bit atomic unsigned int.
+//
+// MSB LSB
+// | |
+// v v
+// [P|C62|...|C1|C0]
+// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
+// Post'ed state: [1|..|0|0]
+// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
+// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
+static constexpr uint64_t kProducerStateBit = 1ULL << 63;
+static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+
+static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
+ uint64_t clear_mask, uint64_t set_mask) {
+ uint64_t old_state;
+ uint64_t new_state;
+ do {
+ old_state = buffer_state->load();
+ new_state = (old_state & ~clear_mask) | set_mask;
+ } while (!buffer_state->compare_exchange_weak(old_state, new_state));
+}
+
+static inline bool IsBufferGained(uint64_t state) { return state == 0; }
+
+static inline bool IsBufferPosted(uint64_t state,
+ uint64_t consumer_bit = kConsumerStateMask) {
+ return (state & kProducerStateBit) && !(state & consumer_bit);
+}
+
+static inline bool IsBufferAcquired(uint64_t state) {
+ return (state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline bool IsBufferReleased(uint64_t state) {
+ return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline uint64_t FindNextClearedBit(uint64_t bits) {
+ return ~bits - (~bits & (~bits - 1));
+}
+
+static inline uint64_t FindFirstClearedBit() {
+ return FindNextClearedBit(kProducerStateBit);
+}
+
+struct __attribute__((packed, aligned(8))) MetadataHeader {
+ // Internal data format, which can be updated as long as the size, padding and
+ // field alignment of the struct is consistent within the same ABI. As this
+ // part is subject for future updates, it's not stable cross Android version,
+ // so don't have it visible from outside of the Android platform (include Apps
+ // and vendor HAL).
+ std::atomic<uint64_t> buffer_state;
+ std::atomic<uint64_t> fence_state;
+ uint64_t queue_index;
+
+ // Public data format, which should be updated with caution. See more details
+ // in dvr_api.h
+ DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+} // namespace BufferHubDefs
+
+} // namespace dvr
+} // namespace android
+
+
+#endif // ANDROID_DVR_BUFFER_HUB_DEFS_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 088a235..e163216 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -1,11 +1,11 @@
#ifndef ANDROID_DVR_BUFFERHUB_RPC_H_
#define ANDROID_DVR_BUFFERHUB_RPC_H_
+#include "buffer_hub_defs.h"
+
#include <cutils/native_handle.h>
-#include <sys/types.h>
#include <ui/BufferQueueDefs.h>
-#include <dvr/dvr_api.h>
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/remote_method.h>
@@ -15,71 +15,6 @@
namespace android {
namespace dvr {
-namespace BufferHubDefs {
-
-static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint32_t kMetadataUsage =
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-
-// Single producuer multiple (up to 63) consumers ownership signal.
-// 64-bit atomic unsigned int.
-//
-// MSB LSB
-// | |
-// v v
-// [P|C62|...|C1|C0]
-// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
-// Post'ed state: [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
-
-static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
- uint64_t clear_mask, uint64_t set_mask) {
- uint64_t old_state;
- uint64_t new_state;
- do {
- old_state = buffer_state->load();
- new_state = (old_state & ~clear_mask) | set_mask;
- } while (!buffer_state->compare_exchange_weak(old_state, new_state));
-}
-
-static inline bool IsBufferGained(uint64_t state) { return state == 0; }
-
-static inline bool IsBufferPosted(uint64_t state,
- uint64_t consumer_bit = kConsumerStateMask) {
- return (state & kProducerStateBit) && !(state & consumer_bit);
-}
-
-static inline bool IsBufferAcquired(uint64_t state) {
- return (state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-static inline bool IsBufferReleased(uint64_t state) {
- return !(state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-struct __attribute__((packed, aligned(8))) MetadataHeader {
- // Internal data format, which can be updated as long as the size, padding and
- // field alignment of the struct is consistent within the same ABI. As this
- // part is subject for future updates, it's not stable cross Android version,
- // so don't have it visible from outside of the Android platform (include Apps
- // and vendor HAL).
- std::atomic<uint64_t> buffer_state;
- std::atomic<uint64_t> fence_state;
- uint64_t queue_index;
-
- // Public data format, which should be updated with caution. See more details
- // in dvr_api.h
- DvrNativeBufferMetadata metadata;
-};
-
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
-static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
-
-} // namespace BufferHubDefs
-
template <typename FileHandleType>
class NativeBufferHandle {
public:
@@ -450,6 +385,7 @@
kOpCreate = kOpDetachedBufferBase,
kOpImport,
kOpPromote,
+ kOpDuplicate,
};
public:
@@ -459,8 +395,9 @@
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, Promote);
+ PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
};
} // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
index 6d0b502..376b53e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
@@ -57,6 +57,9 @@
// return. Further IPCs towards this channel will return error.
pdx::Status<pdx::LocalChannelHandle> Promote();
+ // Creates a DetachedBuffer from an existing one.
+ pdx::Status<pdx::LocalChannelHandle> Duplicate();
+
// Takes the underlying graphic buffer out of this DetachedBuffer. This call
// immediately invalidates this DetachedBuffer object and transfers the
// underlying pdx::LocalChannelHandle into the GraphicBuffer.
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 6122846..499a8f6 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -13,11 +13,12 @@
// limitations under the License.
sourceFiles = [
+ "buffer_channel.cpp",
"buffer_hub.cpp",
+ "buffer_node.cpp",
"bufferhubd.cpp",
"consumer_channel.cpp",
"producer_channel.cpp",
- "detached_buffer_channel.cpp",
"consumer_queue_channel.cpp",
"producer_queue_channel.cpp",
]
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
new file mode 100644
index 0000000..2150d62
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -0,0 +1,206 @@
+#include "buffer_channel.h"
+#include "producer_channel.h"
+
+using android::pdx::BorrowedHandle;
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ int channel_id, IonBuffer buffer,
+ IonBuffer metadata_buffer,
+ size_t user_metadata_size)
+ : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+ buffer_node_(std::make_shared<BufferNode>(
+ std::move(buffer), std::move(metadata_buffer), user_metadata_size)),
+ buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size)
+ : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
+ buffer_node_(std::make_shared<BufferNode>(
+ width, height, layer_count, format, usage, user_metadata_size)),
+ buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ int channel_id,
+ std::shared_ptr<BufferNode> buffer_node,
+ uint64_t buffer_state_bit)
+ : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+ buffer_node_(buffer_node),
+ buffer_state_bit_(buffer_state_bit) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::~BufferChannel() {
+ ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
+ channel_id(), buffer_id());
+ Hangup();
+}
+
+BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
+ return BufferInfo(
+ buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
+ buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
+ buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+ /*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
+ /*index=*/0);
+}
+
+void BufferChannel::HandleImpulse(Message& /*message*/) {
+ ATRACE_NAME("BufferChannel::HandleImpulse");
+}
+
+bool BufferChannel::HandleMessage(Message& message) {
+ ATRACE_NAME("BufferChannel::HandleMessage");
+ switch (message.GetOp()) {
+ case DetachedBufferRPC::Import::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Import>(
+ *this, &BufferChannel::OnImport, message);
+ return true;
+
+ case DetachedBufferRPC::Duplicate::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
+ *this, &BufferChannel::OnDuplicate, message);
+ return true;
+
+ case DetachedBufferRPC::Promote::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Promote>(
+ *this, &BufferChannel::OnPromote, message);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+Status<BufferDescription<BorrowedHandle>> BufferChannel::OnImport(
+ Message& /*message*/) {
+ ATRACE_NAME("BufferChannel::OnImport");
+ ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.",
+ buffer_id());
+
+ return BufferDescription<BorrowedHandle>{buffer_node_->buffer(),
+ buffer_node_->metadata_buffer(),
+ buffer_id(),
+ channel_id(),
+ buffer_state_bit_,
+ BorrowedHandle{},
+ BorrowedHandle{}};
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
+ Message& message) {
+ ATRACE_NAME("BufferChannel::OnDuplicate");
+ ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.",
+ buffer_id());
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
+ status.GetErrorMessage().c_str());
+ return ErrorStatus(ENOMEM);
+ }
+
+ // Try find the next buffer state bit which has not been claimed by any
+ // other buffers yet.
+ uint64_t buffer_state_bit =
+ BufferHubDefs::FindNextClearedBit(buffer_node_->active_buffer_bit_mask() |
+ BufferHubDefs::kProducerStateBit);
+ if (buffer_state_bit == 0ULL) {
+ ALOGE(
+ "BufferChannel::OnDuplicate: reached the maximum mumber of channels "
+ "per buffer node: 63.");
+ return ErrorStatus(E2BIG);
+ }
+
+ auto channel =
+ std::shared_ptr<BufferChannel>(new BufferChannel(
+ service(), buffer_id(), channel_id, buffer_node_, buffer_state_bit));
+ if (!channel) {
+ ALOGE("BufferChannel::OnDuplicate: Invalid buffer.");
+ return ErrorStatus(EINVAL);
+ }
+
+ const auto channel_status =
+ service()->SetChannel(channel_id, std::move(channel));
+ if (!channel_status) {
+ // Technically, this should never fail, as we just pushed the channel. Note
+ // that LOG_FATAL will be stripped out in non-debug build.
+ LOG_FATAL(
+ "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
+ channel_status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnPromote(
+ Message& message) {
+ ATRACE_NAME("BufferChannel::OnPromote");
+ ALOGD_IF(TRACE, "BufferChannel::OnPromote: buffer_id=%d", buffer_id());
+
+ // Check whether this is the channel exclusive owner of the buffer_node_.
+ if (buffer_state_bit_ != buffer_node_->active_buffer_bit_mask()) {
+ ALOGE(
+ "BufferChannel::OnPromote: Cannot promote this BufferChannel as its "
+ "BufferNode is shared between multiple channels. This channel's state "
+ "bit=0x%" PRIx64 ", acitve_buffer_bit_mask=0x%" PRIx64 ".",
+ buffer_state_bit_, buffer_node_->active_buffer_bit_mask());
+ return ErrorStatus(EINVAL);
+ }
+
+ // Note that the new ProducerChannel will have different channel_id, but
+ // inherits the buffer_id from the DetachedBuffer.
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "BufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
+ status.GetErrorMessage().c_str());
+ return ErrorStatus(ENOMEM);
+ }
+
+ IonBuffer buffer = std::move(buffer_node_->buffer());
+ IonBuffer metadata_buffer = std::move(buffer_node_->metadata_buffer());
+ size_t user_metadata_size = buffer_node_->user_metadata_size();
+
+ std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
+ service(), buffer_id(), channel_id, std::move(buffer),
+ std::move(metadata_buffer), user_metadata_size);
+ if (!channel) {
+ ALOGE(
+ "BufferChannel::OnPromote: Failed to create ProducerChannel from a "
+ "BufferChannel, buffer_id=%d.",
+ buffer_id());
+ }
+
+ const auto channel_status =
+ service()->SetChannel(channel_id, std::move(channel));
+ if (!channel_status) {
+ // Technically, this should never fail, as we just pushed the channel. Note
+ // that LOG_FATAL will be stripped out in non-debug build.
+ LOG_FATAL(
+ "BufferChannel::OnPromote: Failed to set new producer buffer channel: "
+ "%s.",
+ channel_status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/bufferhubd/buffer_channel.h b/services/vr/bufferhubd/buffer_channel.h
new file mode 100644
index 0000000..ac99a73
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.h
@@ -0,0 +1,66 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+#include "buffer_node.h"
+
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace dvr {
+
+class BufferChannel : public BufferHubChannel {
+ public:
+ ~BufferChannel() override;
+
+ template <typename... Args>
+ static std::unique_ptr<BufferChannel> Create(Args&&... args) {
+ auto buffer = std::unique_ptr<BufferChannel>(
+ new BufferChannel(std::forward<Args>(args)...));
+ return buffer->IsValid() ? std::move(buffer) : nullptr;
+ }
+
+ // Returns whether the object holds a valid graphic buffer.
+ bool IsValid() const {
+ return buffer_node_ != nullptr && buffer_node_->IsValid();
+ }
+
+ // Captures buffer info for use by BufferHubService::DumpState().
+ BufferInfo GetBufferInfo() const override;
+
+ bool HandleMessage(pdx::Message& message) override;
+ void HandleImpulse(pdx::Message& message) override;
+
+ private:
+ // Creates a detached buffer from existing IonBuffers.
+ BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+ IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size);
+
+ // Allocates a new detached buffer.
+ BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
+ uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size);
+
+ // Creates a detached buffer from an existing BufferNode.
+ BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+ std::shared_ptr<BufferNode> buffer_node,
+ uint64_t buffer_state_bit);
+
+ pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+ pdx::Message& message);
+ pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
+ pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+ // The concrete implementation of the Buffer object.
+ std::shared_ptr<BufferNode> buffer_node_;
+
+ // The state bit of this buffer. Must be one the lower 63 bits.
+ uint64_t buffer_state_bit_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index e57c8ed..c0ee31b 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -13,8 +13,8 @@
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
#include "consumer_channel.h"
-#include "detached_buffer_channel.h"
#include "producer_channel.h"
#include "producer_queue_channel.h"
@@ -267,7 +267,7 @@
return {};
case DetachedBufferRPC::Promote::Opcode:
- // In addition to the message handler in the DetachedBufferChannel's
+ // In addition to the message handler in the BufferChannel's
// HandleMessage method, we also need to invalid the channel. Note that
// this has to be done after HandleMessage returns to make sure the IPC
// request has went back to the client first.
@@ -332,9 +332,9 @@
return ErrorStatus(EALREADY);
}
- std::unique_ptr<DetachedBufferChannel> channel =
- DetachedBufferChannel::Create(this, buffer_id, width, height, layer_count,
- format, usage, user_metadata_size);
+ std::unique_ptr<BufferChannel> channel =
+ BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
+ usage, user_metadata_size);
if (!channel) {
ALOGE(
"BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
new file mode 100644
index 0000000..de22bba
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -0,0 +1,53 @@
+#include "buffer_node.h"
+
+#include <private/dvr/buffer_hub_defs.h>
+
+namespace android {
+namespace dvr {
+
+BufferNode::BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size)
+ : buffer_(std::move(buffer)),
+ metadata_buffer_(std::move(metadata_buffer)),
+ user_metadata_size_(user_metadata_size) {}
+
+// Allocates a new BufferNode.
+BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage,
+ size_t user_metadata_size)
+ : user_metadata_size_(user_metadata_size) {
+ // The size the of metadata buffer is used as the "width" parameter during
+ // allocation. Thus it cannot overflow uint32_t.
+ if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
+ BufferHubDefs::kMetadataHeaderSize)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
+ return;
+ }
+
+ if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+ "buffer: %s",
+ strerror(-ret));
+ return;
+ }
+
+ // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
+ // user requested metadata.
+ const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
+ if (int ret = metadata_buffer_.Alloc(size,
+ /*height=*/1,
+ /*layer_count=*/1,
+ BufferHubDefs::kMetadataFormat,
+ BufferHubDefs::kMetadataUsage)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+ "metadata: %s",
+ strerror(-ret));
+ return;
+ }
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.h b/services/vr/bufferhubd/buffer_node.h
new file mode 100644
index 0000000..4bcf4e3
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+
+#include <private/dvr/ion_buffer.h>
+
+namespace android {
+namespace dvr {
+
+class BufferNode {
+ public:
+ // Creates a BufferNode from existing IonBuffers, i.e. creating from an
+ // existing ProducerChannel.
+ BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size);
+
+ // Allocates a new BufferNode.
+ BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage, size_t user_metadata_size);
+
+ // Returns whether the object holds a valid graphic buffer.
+ bool IsValid() const {
+ return buffer_.IsValid() && metadata_buffer_.IsValid();
+ }
+
+ size_t user_metadata_size() const { return user_metadata_size_; }
+ uint64_t active_buffer_bit_mask() const { return active_buffer_bit_mask_; }
+ void set_buffer_state_bit(uint64_t buffer_state_bit) {
+ active_buffer_bit_mask_ |= buffer_state_bit;
+ }
+
+ // Used to take out IonBuffers.
+ IonBuffer& buffer() { return buffer_; }
+ IonBuffer& metadata_buffer() { return metadata_buffer_; }
+
+ // Used to access IonBuffers.
+ const IonBuffer& buffer() const { return buffer_; }
+ const IonBuffer& metadata_buffer() const { return metadata_buffer_; }
+
+ private:
+ // Gralloc buffer handles.
+ IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
+
+ // Size of user requested metadata.
+ const size_t user_metadata_size_;
+
+ // All active buffer bits. Valid bits are the lower 63 bits, while the
+ // highest bit is reserved for the exclusive writing and should not be set.
+ uint64_t active_buffer_bit_mask_ = 0ULL;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
deleted file mode 100644
index 3061805..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-#include "detached_buffer_channel.h"
-#include "producer_channel.h"
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
- int buffer_id, int channel_id,
- IonBuffer buffer,
- IonBuffer metadata_buffer,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_(std::move(buffer)),
- metadata_buffer_(std::move(metadata_buffer)),
- user_metadata_size_(user_metadata_size) {
-}
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
- int buffer_id, uint32_t width,
- uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
- user_metadata_size_(user_metadata_size) {
- // The size the of metadata buffer is used as the "width" parameter during
- // allocation. Thus it cannot overflow uint32_t.
- if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
- BufferHubDefs::kMetadataHeaderSize)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
- return;
- }
-
- if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "buffer: %s",
- strerror(-ret));
- return;
- }
-
- // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
- // user requested metadata.
- const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
- if (int ret = metadata_buffer_.Alloc(size,
- /*height=*/1,
- /*layer_count=*/1,
- BufferHubDefs::kMetadataFormat,
- BufferHubDefs::kMetadataUsage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "metadata: %s",
- strerror(-ret));
- return;
- }
-}
-
-DetachedBufferChannel::~DetachedBufferChannel() {
- ALOGD_IF(TRACE,
- "DetachedBufferChannel::~DetachedBufferChannel: channel_id=%d "
- "buffer_id=%d.",
- channel_id(), buffer_id());
- Hangup();
-}
-
-BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
- return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
- buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), /*pending_count=*/0, /*state=*/0,
- /*signaled_mask=*/0, /*index=*/0);
-}
-
-void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
- ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
-}
-
-bool DetachedBufferChannel::HandleMessage(Message& message) {
- ATRACE_NAME("DetachedBufferChannel::HandleMessage");
- switch (message.GetOp()) {
- case DetachedBufferRPC::Import::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Import>(
- *this, &DetachedBufferChannel::OnImport, message);
- return true;
-
- case DetachedBufferRPC::Promote::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Promote>(
- *this, &DetachedBufferChannel::OnPromote, message);
- return true;
-
- default:
- return false;
- }
-}
-
-Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport(
- Message& /*message*/) {
- ATRACE_NAME("DetachedBufferChannel::OnGetBuffer");
- ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.",
- buffer_id());
-
- return BufferDescription<BorrowedHandle>{buffer_,
- metadata_buffer_,
- buffer_id(),
- channel_id(),
- /*buffer_state_bit=*/0,
- BorrowedHandle{},
- BorrowedHandle{}};
-}
-
-Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
- Message& message) {
- ATRACE_NAME("DetachedBufferChannel::OnPromote");
- ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
- buffer_id());
-
- // Note that the new ProducerChannel will have different channel_id, but
- // inherits the buffer_id from the DetachedBuffer.
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "DetachedBufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
- std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
- if (!channel) {
- ALOGE(
- "DetachedBufferChannel::OnPromote: Failed to create ProducerChannel "
- "from a DetachedBufferChannel, buffer_id=%d.",
- buffer_id());
- }
-
- const auto channel_status =
- service()->SetChannel(channel_id, std::move(channel));
- if (!channel_status) {
- // Technically, this should never fail, as we just pushed the channel. Note
- // that LOG_FATAL will be stripped out in non-debug build.
- LOG_FATAL(
- "DetachedBufferChannel::OnPromote: Failed to set new producer buffer "
- "channel: %s.",
- channel_status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
deleted file mode 100644
index 8b6dab8..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-
-#include "buffer_hub.h"
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-
-namespace android {
-namespace dvr {
-
-class DetachedBufferChannel : public BufferHubChannel {
- public:
- ~DetachedBufferChannel() override;
-
- template <typename... Args>
- static std::unique_ptr<DetachedBufferChannel> Create(Args&&... args) {
- auto buffer = std::unique_ptr<DetachedBufferChannel>(
- new DetachedBufferChannel(std::forward<Args>(args)...));
- return buffer->IsValid() ? std::move(buffer) : nullptr;
- }
-
- // Returns whether the object holds a valid graphic buffer.
- bool IsValid() const {
- return buffer_.IsValid() && metadata_buffer_.IsValid();
- }
-
- size_t user_metadata_size() const { return user_metadata_size_; }
-
- // Captures buffer info for use by BufferHubService::DumpState().
- BufferInfo GetBufferInfo() const override;
-
- bool HandleMessage(pdx::Message& message) override;
- void HandleImpulse(pdx::Message& message) override;
-
- private:
- // Creates a detached buffer from existing IonBuffers.
- DetachedBufferChannel(BufferHubService* service, int buffer_id,
- int channel_id, IonBuffer buffer,
- IonBuffer metadata_buffer, size_t user_metadata_size);
-
- // Allocates a new detached buffer.
- DetachedBufferChannel(BufferHubService* service, int buffer_id,
- uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size);
-
- pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
- pdx::Message& message);
- pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
-
- // Gralloc buffer handles.
- IonBuffer buffer_;
- IonBuffer metadata_buffer_;
-
- // Size of user requested metadata.
- const size_t user_metadata_size_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 97af660..19d48f2 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -12,8 +12,8 @@
#include <thread>
#include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
#include "consumer_channel.h"
-#include "detached_buffer_channel.h"
using android::pdx::BorrowedHandle;
using android::pdx::ErrorStatus;
@@ -27,14 +27,6 @@
namespace android {
namespace dvr {
-namespace {
-
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
- return ~bits - (~bits & (~bits - 1));
-}
-
-} // namespace
-
ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
int channel_id, IonBuffer buffer,
IonBuffer metadata_buffer,
@@ -270,7 +262,7 @@
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
- uint64_t consumer_state_bit = FindNextClearedBit(
+ uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
BufferHubDefs::kProducerStateBit);
if (consumer_state_bit == 0ULL) {
@@ -419,10 +411,9 @@
return ErrorStatus(-ret);
};
- std::unique_ptr<DetachedBufferChannel> channel =
- DetachedBufferChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
+ std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
+ service(), buffer_id(), channel_id, std::move(buffer_),
+ std::move(metadata_buffer_), user_metadata_size_);
if (!channel) {
ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
return ErrorStatus(EINVAL);