diff options
author | 2018-05-03 17:51:52 -0700 | |
---|---|---|
committer | 2018-05-17 18:35:59 -0700 | |
commit | 57ae3eea6d0d3a337bd2e41c33d82edf6e73a189 (patch) | |
tree | 1cc39a7993782a48ca32e287cb20f99fb8164e8b | |
parent | 4287535fd25cdddd0ae0814c1426aea2b9371e3e (diff) |
Implement BufferHubProducer::attachBuffer
1/ Introduce new kOpProducerQueueInsertBuffer operation to insert a
standalone ProducerChannel into a ProducerQueueChannel.
2/ Introduce some PDX security check against channel_id spoofing.
Bug: 69981968
Bug: 79224574
Test: buffer_hub_queue-test, libgui_test
Change-Id: I3c13e2897476c34e6e939756b079fe3440937236
-rw-r--r-- | libs/gui/Android.bp | 2 | ||||
-rw-r--r-- | libs/gui/BufferHubProducer.cpp | 88 | ||||
-rw-r--r-- | libs/gui/tests/IGraphicBufferProducer_test.cpp | 27 | ||||
-rw-r--r-- | libs/vr/libbufferhub/buffer_hub_client.cpp | 7 | ||||
-rw-r--r-- | libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h | 7 | ||||
-rw-r--r-- | libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h | 12 | ||||
-rw-r--r-- | libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp | 34 | ||||
-rw-r--r-- | libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h | 7 | ||||
-rw-r--r-- | libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp | 34 | ||||
-rw-r--r-- | libs/vr/libpdx/private/pdx/service.h | 9 | ||||
-rw-r--r-- | libs/vr/libpdx_uds/service_endpoint.cpp | 3 | ||||
-rw-r--r-- | services/vr/bufferhubd/detached_buffer_channel.cpp | 1 | ||||
-rw-r--r-- | services/vr/bufferhubd/producer_channel.cpp | 10 | ||||
-rw-r--r-- | services/vr/bufferhubd/producer_channel.h | 2 | ||||
-rw-r--r-- | services/vr/bufferhubd/producer_queue_channel.cpp | 80 | ||||
-rw-r--r-- | services/vr/bufferhubd/producer_queue_channel.h | 8 |
16 files changed, 312 insertions, 19 deletions
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index b29c1d5157..ef3e592c09 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -123,6 +123,7 @@ cc_library_shared { "android.hardware.graphics.common@1.1", "libsync", "libbinder", + "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. "libpdx_default_transport", "libcutils", @@ -149,6 +150,7 @@ cc_library_shared { "BufferHubProducer.cpp", ], exclude_shared_libs: [ + "libbufferhub", "libbufferhubqueue", "libpdx_default_transport", ], diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp index 2bc194aead..06d597ccfa 100644 --- a/libs/gui/BufferHubProducer.cpp +++ b/libs/gui/BufferHubProducer.cpp @@ -18,6 +18,7 @@ #include <gui/BufferHubProducer.h> #include <inttypes.h> #include <log/log.h> +#include <private/dvr/detached_buffer.h> #include <system/window.h> #include <ui/DetachedBufferHandle.h> @@ -363,13 +364,86 @@ status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<F return error; } -status_t BufferHubProducer::attachBuffer(int* /* out_slot */, - const sp<GraphicBuffer>& /* buffer */) { - // With this BufferHub backed implementation, we assume (for now) all buffers - // are allocated and owned by the BufferHub. Thus the attempt of transfering - // ownership of a buffer to the buffer queue is intentionally unsupported. - LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported."); - return INVALID_OPERATION; +status_t BufferHubProducer::attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) { + // In the BufferHub design, all buffers are allocated and owned by the BufferHub. Thus only + // GraphicBuffers that are originated from BufferHub can be attached to a BufferHubProducer. + ALOGV("queueBuffer: buffer=%p", buffer.get()); + + if (out_slot == nullptr) { + ALOGE("attachBuffer: out_slot cannot be NULL."); + return BAD_VALUE; + } + if (buffer == nullptr || !buffer->isDetachedBuffer()) { + ALOGE("attachBuffer: invalid GraphicBuffer."); + return BAD_VALUE; + } + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("attachBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + // Before attaching the buffer, caller is supposed to call + // IGraphicBufferProducer::setGenerationNumber to inform the + // BufferHubProducer the next generation number. + if (buffer->getGenerationNumber() != generation_number_) { + ALOGE("attachBuffer: Mismatched generation number, buffer: %u, queue: %u.", + buffer->getGenerationNumber(), generation_number_); + return BAD_VALUE; + } + + // Creates a BufferProducer from the GraphicBuffer. + std::unique_ptr<DetachedBufferHandle> detached_handle = buffer->takeDetachedBufferHandle(); + if (detached_handle == nullptr) { + ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL."); + return BAD_VALUE; + } + auto detached_buffer = DetachedBuffer::Import(std::move(detached_handle->handle())); + if (detached_buffer == nullptr) { + ALOGE("attachBuffer: DetachedBuffer cannot be NULL."); + return BAD_VALUE; + } + auto status_or_handle = detached_buffer->Promote(); + if (!status_or_handle.ok()) { + ALOGE("attachBuffer: Failed to promote a DetachedBuffer into a BufferProducer, error=%d.", + status_or_handle.error()); + return BAD_VALUE; + } + std::shared_ptr<BufferProducer> buffer_producer = + BufferProducer::Import(status_or_handle.take()); + if (buffer_producer == nullptr) { + ALOGE("attachBuffer: Failed to import BufferProducer."); + return BAD_VALUE; + } + + // Adds the BufferProducer into the Queue. + auto status_or_slot = queue_->InsertBuffer(buffer_producer); + if (!status_or_slot.ok()) { + ALOGE("attachBuffer: Failed to insert buffer, error=%d.", status_or_slot.error()); + return BAD_VALUE; + } + + size_t slot = status_or_slot.get(); + ALOGV("attachBuffer: returning slot %zu.", slot); + if (slot >= static_cast<size_t>(max_buffer_count_)) { + ALOGE("attachBuffer: Invalid slot: %zu.", slot); + return BAD_VALUE; + } + + // The just attached buffer should be in dequeued state according to IGraphicBufferProducer + // interface. In BufferHub's language the buffer should be in Gained state. + buffers_[slot].mGraphicBuffer = buffer; + buffers_[slot].mBufferState.attachProducer(); + buffers_[slot].mEglFence = EGL_NO_SYNC_KHR; + buffers_[slot].mFence = Fence::NO_FENCE; + buffers_[slot].mRequestBufferCalled = true; + buffers_[slot].mAcquireCalled = false; + buffers_[slot].mNeedsReallocation = false; + + *out_slot = static_cast<int>(slot); + return NO_ERROR; } status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input, diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index e5a4adbaba..c20e8fca21 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -787,10 +787,31 @@ TEST_P(IGraphicBufferProducerTest, ASSERT_OK(mProducer->disconnect(TEST_API)); - if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { - // TODO(b/69981968): Implement BufferHubProducer::attachBuffer - ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); + ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); +} + +TEST_P(IGraphicBufferProducerTest, DetachThenAttach_Succeeds) { + int slot = -1; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + + setupDequeueRequestBuffer(&slot, &fence, &buffer); + ASSERT_TRUE(buffer != nullptr); + + ASSERT_OK(mProducer->detachBuffer(slot)); + EXPECT_OK(buffer->initCheck()); + + if (GetParam() == USE_BUFFER_HUB_PRODUCER) { + // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have + // isDetachedBuffer() set. Note that this only applies to BufferHub. + EXPECT_TRUE(buffer->isDetachedBuffer()); + } else { + EXPECT_FALSE(buffer->isDetachedBuffer()); } + + EXPECT_OK(mProducer->attachBuffer(&slot, buffer)); + EXPECT_FALSE(buffer->isDetachedBuffer()); + EXPECT_OK(buffer->initCheck()); } #if USE_BUFFER_HUB_AS_BUFFER_QUEUE diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp index 159f2bd1b3..577cba9572 100644 --- a/libs/vr/libbufferhub/buffer_hub_client.cpp +++ b/libs/vr/libbufferhub/buffer_hub_client.cpp @@ -42,11 +42,13 @@ LocalChannelHandle BufferHubClient::TakeChannelHandle() { BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle) : Client{pdx::default_transport::ClientChannel::Create( std::move(channel_handle))}, - id_(-1) {} + id_(-1), + cid_(-1) {} BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path) : Client{pdx::default_transport::ClientChannelFactory::Create( endpoint_path)}, - id_(-1) {} + id_(-1), + cid_(-1) {} BufferHubBuffer::~BufferHubBuffer() { if (metadata_header_ != nullptr) { @@ -136,6 +138,7 @@ int BufferHubBuffer::ImportBuffer() { } id_ = new_id; + cid_ = buffer_desc.buffer_cid(); buffer_state_bit_ = buffer_desc.buffer_state_bit(); // Note that here the buffer state is mapped from shared memory as an atomic diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h index 0ea77c85fb..b71f5dcba6 100644 --- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h +++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h @@ -107,8 +107,14 @@ class BufferHubBuffer : public pdx::Client { IonBuffer* buffer() { return &buffer_; } const IonBuffer* buffer() const { return &buffer_; } + // Gets 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_; } + // Gets the channel id of the buffer client. Each BufferHubBuffer client has + // its system unique channel id. + int cid() const { return cid_; } + // Returns the buffer buffer state. uint64_t buffer_state() { return buffer_state_->load(); }; @@ -170,6 +176,7 @@ class BufferHubBuffer : public pdx::Client { // for logging and debugging purposes only and should not be used for lookup // or any other functional purpose as a security precaution. int id_; + int cid_; uint64_t buffer_state_bit_{0ULL}; IonBuffer buffer_; IonBuffer metadata_buffer_; diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h index f4918c497e..088a235e7e 100644 --- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h +++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h @@ -164,10 +164,11 @@ class BufferDescription { public: BufferDescription() = default; BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id, - uint64_t buffer_state_bit, + int buffer_cid, uint64_t buffer_state_bit, const FileHandleType& acquire_fence_fd, const FileHandleType& release_fence_fd) : id_(id), + buffer_cid_(buffer_cid), buffer_state_bit_(buffer_state_bit), buffer_(buffer, id), metadata_(metadata, id), @@ -180,6 +181,9 @@ class BufferDescription { // 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_; } + // Channel ID of the buffer client. Each BufferHubBuffer client has its system + // unique channel id. + int buffer_cid() const { return buffer_cid_; } // 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 @@ -193,6 +197,7 @@ class BufferDescription { private: int id_{-1}; + int buffer_cid_{-1}; uint64_t buffer_state_bit_{0}; // Two IonBuffers: one for the graphic buffer and one for metadata. NativeBufferHandle<FileHandleType> buffer_; @@ -202,7 +207,7 @@ class BufferDescription { FileHandleType acquire_fence_fd_; FileHandleType release_fence_fd_; - PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_, + PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_, buffer_cid_, buffer_state_bit_, buffer_, metadata_, acquire_fence_fd_, release_fence_fd_); @@ -381,6 +386,7 @@ struct BufferHubRPC { kOpCreateConsumerQueue, kOpGetQueueInfo, kOpProducerQueueAllocateBuffers, + kOpProducerQueueInsertBuffer, kOpProducerQueueRemoveBuffer, kOpConsumerQueueImportBuffers, // TODO(b/77153033): Separate all those RPC operations into subclasses. @@ -430,6 +436,8 @@ struct BufferHubRPC { std::vector<std::pair<LocalChannelHandle, size_t>>( uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage, size_t buffer_count)); + PDX_REMOTE_METHOD(ProducerQueueInsertBuffer, kOpProducerQueueInsertBuffer, + size_t(int buffer_cid)); PDX_REMOTE_METHOD(ProducerQueueRemoveBuffer, kOpProducerQueueRemoveBuffer, void(size_t slot)); PDX_REMOTE_METHOD(ConsumerQueueImportBuffers, kOpConsumerQueueImportBuffers, diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index 8feb1cd803..1f2c51765d 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -524,6 +524,40 @@ Status<void> ProducerQueue::AddBuffer( return BufferHubQueue::Enqueue({buffer, slot, 0ULL}); } +Status<size_t> ProducerQueue::InsertBuffer( + const std::shared_ptr<BufferProducer>& buffer) { + if (buffer == nullptr || + !BufferHubDefs::IsBufferGained(buffer->buffer_state())) { + ALOGE( + "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in " + "gained state."); + return ErrorStatus(EINVAL); + } + + auto status_or_slot = + InvokeRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>( + buffer->cid()); + if (!status_or_slot) { + ALOGE( + "ProducerQueue::InsertBuffer: Failed to insert producer buffer: " + "buffer_cid=%d, error: %s.", + buffer->cid(), status_or_slot.GetErrorMessage().c_str()); + return status_or_slot.error_status(); + } + + size_t slot = status_or_slot.get(); + + // Note that we are calling AddBuffer() from the base class to explicitly + // avoid Enqueue() the BufferProducer. + auto status = BufferHubQueue::AddBuffer(buffer, slot); + if (!status) { + ALOGE("ProducerQueue::InsertBuffer: Failed to add buffer: %s.", + status.GetErrorMessage().c_str()); + return status.error_status(); + } + return {slot}; +} + Status<void> ProducerQueue::RemoveBuffer(size_t slot) { auto status = InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot); diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index 60e1c4b8a9..df500b493e 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h @@ -331,6 +331,13 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { pdx::Status<void> AddBuffer(const std::shared_ptr<BufferProducer>& buffer, size_t slot); + // Inserts a ProducerBuffer into the queue. On success, the method returns the + // |slot| number where the new buffer gets inserted. Note that the buffer + // being inserted should be in Gain'ed state prior to the call and it's + // considered as already Dequeued when the function returns. + pdx::Status<size_t> InsertBuffer( + const std::shared_ptr<BufferProducer>& buffer); + // Remove producer buffer from the queue. pdx::Status<void> RemoveBuffer(size_t slot) override; diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp index 47a27344bd..2975f56928 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp @@ -181,6 +181,40 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { } } +TEST_F(BufferHubQueueTest, TestInsertBuffer) { + ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); + + consumer_queue_ = producer_queue_->CreateConsumerQueue(); + ASSERT_TRUE(consumer_queue_ != nullptr); + EXPECT_EQ(producer_queue_->capacity(), 0); + EXPECT_EQ(consumer_queue_->capacity(), 0); + + std::shared_ptr<BufferProducer> p1 = BufferProducer::Create( + kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage, 0); + ASSERT_TRUE(p1 != nullptr); + + // Inserting a posted buffer will fail. + DvrNativeBufferMetadata meta; + EXPECT_EQ(p1->PostAsync(&meta, LocalHandle()), 0); + auto status_or_slot = producer_queue_->InsertBuffer(p1); + EXPECT_FALSE(status_or_slot.ok()); + EXPECT_EQ(status_or_slot.error(), EINVAL); + + // Inserting a gained buffer will succeed. + std::shared_ptr<BufferProducer> p2 = BufferProducer::Create( + kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage); + ASSERT_TRUE(p2 != nullptr); + status_or_slot = producer_queue_->InsertBuffer(p2); + EXPECT_TRUE(status_or_slot.ok()); + // This is the first buffer inserted, should take slot 0. + size_t slot = status_or_slot.get(); + EXPECT_EQ(slot, 0); + + // Wait and expect the consumer to kick up the newly inserted buffer. + WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs); + EXPECT_EQ(consumer_queue_->capacity(), 1ULL); +} + TEST_F(BufferHubQueueTest, TestRemoveBuffer) { ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); DvrNativeBufferMetadata mo; diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h index 13aa3e90d7..15fa327e45 100644 --- a/libs/vr/libpdx/private/pdx/service.h +++ b/libs/vr/libpdx/private/pdx/service.h @@ -59,9 +59,18 @@ class Channel : public std::enable_shared_from_this<Channel> { virtual ~Channel() {} /* + * Accessors to the pid of the last active client. + */ + pid_t GetActiveProcessId() const { return client_pid_; } + void SetActiveProcessId(pid_t pid) { client_pid_ = pid; } + + /* * Utility to get a shared_ptr reference from the channel context pointer. */ static std::shared_ptr<Channel> GetFromMessageInfo(const MessageInfo& info); + + private: + pid_t client_pid_ = 0; }; /* diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp index 32d40e8371..ecbfdba7c4 100644 --- a/libs/vr/libpdx_uds/service_endpoint.cpp +++ b/libs/vr/libpdx_uds/service_endpoint.cpp @@ -521,6 +521,9 @@ Status<void> Endpoint::ReceiveMessageForChannel( info.flags = 0; info.service = service_; info.channel = GetChannelState(channel_id); + if (info.channel != nullptr) { + info.channel->SetActiveProcessId(request.cred.pid); + } info.send_len = request.send_len; info.recv_len = request.max_recv_len; info.fd_count = request.file_descriptors.size(); diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp index a5cf68dcfd..306180578f 100644 --- a/services/vr/bufferhubd/detached_buffer_channel.cpp +++ b/services/vr/bufferhubd/detached_buffer_channel.cpp @@ -109,6 +109,7 @@ Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport( return BufferDescription<BorrowedHandle>{buffer_, metadata_buffer_, buffer_id(), + channel_id(), /*buffer_state_bit=*/0, BorrowedHandle{}, BorrowedHandle{}}; diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index b6977aaa63..97af660e5d 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -236,9 +236,13 @@ bool ProducerChannel::HandleMessage(Message& message) { BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer( uint64_t buffer_state_bit) { - return { - buffer_, metadata_buffer_, buffer_id(), - buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()}; + return {buffer_, + metadata_buffer_, + buffer_id(), + channel_id(), + buffer_state_bit, + acquire_fence_fd_.Borrow(), + release_fence_fd_.Borrow()}; } Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer( diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h index 67fdf150a0..10a4ce7c71 100644 --- a/services/vr/bufferhubd/producer_channel.h +++ b/services/vr/bufferhubd/producer_channel.h @@ -43,6 +43,8 @@ class ProducerChannel : public BufferHubChannel { ~ProducerChannel() override; + uint64_t buffer_state() const { return buffer_state_->load(); } + bool HandleMessage(Message& message) override; void HandleImpulse(Message& message) override; diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp index c0c48c2dc1..88f5508307 100644 --- a/services/vr/bufferhubd/producer_queue_channel.cpp +++ b/services/vr/bufferhubd/producer_queue_channel.cpp @@ -76,6 +76,11 @@ bool ProducerQueueChannel::HandleMessage(Message& message) { message); return true; + case BufferHubRPC::ProducerQueueInsertBuffer::Opcode: + DispatchRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>( + *this, &ProducerQueueChannel::OnProducerQueueInsertBuffer, message); + return true; + case BufferHubRPC::ProducerQueueRemoveBuffer::Opcode: DispatchRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>( *this, &ProducerQueueChannel::OnProducerQueueRemoveBuffer, message); @@ -278,6 +283,81 @@ ProducerQueueChannel::AllocateBuffer(Message& message, uint32_t width, return {{std::move(buffer_handle), slot}}; } +Status<size_t> ProducerQueueChannel::OnProducerQueueInsertBuffer( + pdx::Message& message, int buffer_cid) { + ATRACE_NAME("ProducerQueueChannel::InsertBuffer"); + ALOGD_IF(TRACE, + "ProducerQueueChannel::InsertBuffer: channel_id=%d, buffer_cid=%d", + channel_id(), buffer_cid); + + if (capacity_ >= BufferHubRPC::kMaxQueueCapacity) { + ALOGE("ProducerQueueChannel::InsertBuffer: reaches kMaxQueueCapacity."); + return ErrorStatus(E2BIG); + } + auto producer_channel = std::static_pointer_cast<ProducerChannel>( + service()->GetChannel(buffer_cid)); + if (producer_channel == nullptr || + producer_channel->channel_type() != BufferHubChannel::kProducerType) { + // Rejects the request if the requested buffer channel is invalid and/or + // it's not a ProducerChannel. + ALOGE( + "ProducerQueueChannel::InsertBuffer: Invalid buffer_cid=%d, " + "producer_buffer=0x%p, channel_type=%d.", + buffer_cid, producer_channel.get(), + producer_channel == nullptr ? -1 : producer_channel->channel_type()); + return ErrorStatus(EINVAL); + } + if (producer_channel->GetActiveProcessId() != message.GetProcessId()) { + // Rejects the request if the requested buffer channel is not currently + // connected to the caller this is IPC request. This effectively prevents + // fake buffer_cid from being injected. + ALOGE( + "ProducerQueueChannel::InsertBuffer: Requested buffer channel " + "(buffer_cid=%d) is not connected to the calling process (pid=%d). " + "It's connected to a different process (pid=%d).", + buffer_cid, message.GetProcessId(), + producer_channel->GetActiveProcessId()); + return ErrorStatus(EINVAL); + } + uint64_t buffer_state = producer_channel->buffer_state(); + if (!BufferHubDefs::IsBufferGained(buffer_state)) { + // Rejects the request if the requested buffer is not in Gained state. + ALOGE( + "ProducerQueueChannel::InsertBuffer: The buffer (cid=%d, " + "state=0x%" PRIx64 ") is not in gained state.", + buffer_cid, buffer_state); + return ErrorStatus(EINVAL); + } + + // Register the to-be-inserted buffer's channel_id into the first empty + // buffer slot. + size_t slot = 0; + for (; slot < BufferHubRPC::kMaxQueueCapacity; slot++) { + if (buffers_[slot].expired()) + break; + } + if (slot == BufferHubRPC::kMaxQueueCapacity) { + ALOGE( + "ProducerQueueChannel::AllocateBuffer: Cannot find empty slot for new " + "buffer allocation."); + return ErrorStatus(E2BIG); + } + + buffers_[slot] = producer_channel; + capacity_++; + + // Notify each consumer channel about the new buffer. + for (auto* consumer_channel : consumer_channels_) { + ALOGD( + "ProducerQueueChannel::AllocateBuffer: Notified consumer with new " + "buffer, buffer_cid=%d", + buffer_cid); + consumer_channel->RegisterNewBuffer(producer_channel, slot); + } + + return {slot}; +} + Status<void> ProducerQueueChannel::OnProducerQueueRemoveBuffer( Message& /*message*/, size_t slot) { if (buffers_[slot].expired()) { diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h index e825f47774..e4fa24372a 100644 --- a/services/vr/bufferhubd/producer_queue_channel.h +++ b/services/vr/bufferhubd/producer_queue_channel.h @@ -38,8 +38,12 @@ class ProducerQueueChannel : public BufferHubChannel { uint32_t format, uint64_t usage, size_t buffer_count); - // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must - // be in Gain'ed state for the producer queue to detach. + // Inserts a BufferProducer into the queue. Note that the buffer must be in + // Gain'ed state for the operation to succeed. + pdx::Status<size_t> OnProducerQueueInsertBuffer(pdx::Message& message, int buffer_cid); + + // Removes a BufferProducer indicated by |slot|. Note that the buffer must be + // in Gain'ed state for the operation to succeed. pdx::Status<void> OnProducerQueueRemoveBuffer(pdx::Message& message, size_t slot); |