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/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