#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::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( *this, &DetachedBufferChannel::OnImport, message); return true; case DetachedBufferRPC::Promote::Opcode: DispatchRemoteMethod( *this, &DetachedBufferChannel::OnPromote, message); return true; default: return false; } } Status> DetachedBufferChannel::OnImport( Message& /*message*/) { ATRACE_NAME("DetachedBufferChannel::OnGetBuffer"); ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.", buffer_id()); return BufferDescription{buffer_, metadata_buffer_, buffer_id(), /*buffer_state_bit=*/0, BorrowedHandle{}, BorrowedHandle{}}; } Status 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 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