| #include <private/dvr/buffer_hub_client.h> |
| |
| #include <log/log.h> |
| #include <poll.h> |
| #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
| #include <utils/Trace.h> |
| |
| #include <mutex> |
| |
| #include <pdx/default_transport/client_channel.h> |
| #include <pdx/default_transport/client_channel_factory.h> |
| |
| #include "include/private/dvr/bufferhub_rpc.h" |
| |
| using android::pdx::LocalHandle; |
| using android::pdx::LocalChannelHandle; |
| using android::pdx::rpc::WrapBuffer; |
| using android::pdx::Status; |
| |
| namespace android { |
| namespace dvr { |
| |
| BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle) |
| : Client{pdx::default_transport::ClientChannel::Create( |
| std::move(channel_handle))}, |
| id_(-1) {} |
| BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path) |
| : Client{pdx::default_transport::ClientChannelFactory::Create( |
| endpoint_path)}, |
| id_(-1) {} |
| |
| BufferHubBuffer::~BufferHubBuffer() {} |
| |
| Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { |
| Status<LocalChannelHandle> status = |
| InvokeRemoteMethod<BufferHubRPC::NewConsumer>(); |
| ALOGE_IF(!status, |
| "BufferHub::CreateConsumer: Failed to create consumer channel: %s", |
| status.GetErrorMessage().c_str()); |
| return status; |
| } |
| |
| int BufferHubBuffer::ImportBuffer() { |
| ATRACE_NAME("BufferHubBuffer::ImportBuffer"); |
| |
| Status<NativeBufferHandle<LocalHandle>> status = |
| InvokeRemoteMethod<BufferHubRPC::GetBuffer>(); |
| if (!status) { |
| ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s", |
| status.GetErrorMessage().c_str()); |
| return -status.error(); |
| } else if (status.get().id() < 0) { |
| ALOGE("BufferHubBuffer::ImportBuffer: Received an invalid id!"); |
| return -EIO; |
| } |
| |
| auto buffer_handle = status.take(); |
| |
| // Stash the buffer id to replace the value in id_. |
| const int new_id = buffer_handle.id(); |
| |
| // Import the buffer. |
| IonBuffer ion_buffer; |
| ALOGD_IF( |
| TRACE, "BufferHubBuffer::ImportBuffer: id=%d FdCount=%zu IntCount=%zu", |
| buffer_handle.id(), buffer_handle.FdCount(), buffer_handle.IntCount()); |
| |
| const int ret = buffer_handle.Import(&ion_buffer); |
| if (ret < 0) |
| return ret; |
| |
| // If the import succeeds, replace the previous buffer and id. |
| buffer_ = std::move(ion_buffer); |
| id_ = new_id; |
| return 0; |
| } |
| |
| int BufferHubBuffer::Poll(int timeout_ms) { |
| ATRACE_NAME("BufferHubBuffer::Poll"); |
| pollfd p = {event_fd(), POLLIN, 0}; |
| return poll(&p, 1, timeout_ms); |
| } |
| |
| int BufferHubBuffer::Lock(int usage, int x, int y, int width, int height, |
| void** address) { |
| return buffer_.Lock(usage, x, y, width, height, address); |
| } |
| |
| int BufferHubBuffer::Unlock() { return buffer_.Unlock(); } |
| |
| int BufferHubBuffer::GetBlobReadWritePointer(size_t size, void** addr) { |
| int width = static_cast<int>(size); |
| int height = 1; |
| int ret = Lock(usage(), 0, 0, width, height, addr); |
| if (ret == 0) |
| Unlock(); |
| return ret; |
| } |
| |
| int BufferHubBuffer::GetBlobReadOnlyPointer(size_t size, void** addr) { |
| return GetBlobReadWritePointer(size, addr); |
| } |
| |
| void BufferHubBuffer::GetBlobFds(int* fds, size_t* fds_count, |
| size_t max_fds_count) const { |
| size_t numFds = static_cast<size_t>(native_handle()->numFds); |
| *fds_count = std::min(max_fds_count, numFds); |
| std::copy(native_handle()->data, native_handle()->data + *fds_count, fds); |
| } |
| |
| BufferConsumer::BufferConsumer(LocalChannelHandle channel) |
| : BASE(std::move(channel)) { |
| const int ret = ImportBuffer(); |
| if (ret < 0) { |
| ALOGE("BufferConsumer::BufferConsumer: Failed to import buffer: %s", |
| strerror(-ret)); |
| Close(ret); |
| } |
| } |
| |
| std::unique_ptr<BufferConsumer> BufferConsumer::Import( |
| LocalChannelHandle channel) { |
| ATRACE_NAME("BufferConsumer::Import"); |
| ALOGD_IF(TRACE, "BufferConsumer::Import: channel=%d", channel.value()); |
| return BufferConsumer::Create(std::move(channel)); |
| } |
| |
| std::unique_ptr<BufferConsumer> BufferConsumer::Import( |
| Status<LocalChannelHandle> status) { |
| return Import(status ? status.take() |
| : LocalChannelHandle{nullptr, -status.error()}); |
| } |
| |
| int BufferConsumer::Acquire(LocalHandle* ready_fence) { |
| return Acquire(ready_fence, nullptr, 0); |
| } |
| |
| int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta, |
| size_t meta_size_bytes) { |
| ATRACE_NAME("BufferConsumer::Acquire"); |
| LocalFence fence; |
| auto return_value = |
| std::make_pair(std::ref(fence), WrapBuffer(meta, meta_size_bytes)); |
| auto status = InvokeRemoteMethodInPlace<BufferHubRPC::ConsumerAcquire>( |
| &return_value, meta_size_bytes); |
| if (status && ready_fence) |
| *ready_fence = fence.take(); |
| return status ? 0 : -status.error(); |
| } |
| |
| int BufferConsumer::Release(const LocalHandle& release_fence) { |
| ATRACE_NAME("BufferConsumer::Release"); |
| return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>( |
| BorrowedFence(release_fence.Borrow()))); |
| } |
| |
| int BufferConsumer::ReleaseAsync() { |
| ATRACE_NAME("BufferConsumer::ReleaseAsync"); |
| return ReturnStatusOrError( |
| SendImpulse(BufferHubRPC::ConsumerRelease::Opcode)); |
| } |
| |
| int BufferConsumer::Discard() { return Release(LocalHandle()); } |
| |
| int BufferConsumer::SetIgnore(bool ignore) { |
| return ReturnStatusOrError( |
| InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore)); |
| } |
| |
| BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, |
| uint32_t usage, size_t metadata_size) |
| : BufferProducer(width, height, format, usage, usage, metadata_size) {} |
| |
| BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, |
| uint64_t producer_usage, uint64_t consumer_usage, |
| size_t metadata_size) |
| : BASE(BufferHubRPC::kClientPath) { |
| ATRACE_NAME("BufferProducer::BufferProducer"); |
| ALOGD_IF(TRACE, |
| "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u " |
| "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 |
| " metadata_size=%zu", |
| event_fd(), width, height, format, producer_usage, consumer_usage, |
| metadata_size); |
| |
| // (b/37881101) Deprecate producer/consumer usage |
| auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( |
| width, height, format, (producer_usage | consumer_usage), metadata_size); |
| if (!status) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to create producer buffer: %s", |
| status.GetErrorMessage().c_str()); |
| Close(-status.error()); |
| return; |
| } |
| |
| const int ret = ImportBuffer(); |
| if (ret < 0) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to import producer buffer: %s", |
| strerror(-ret)); |
| Close(ret); |
| } |
| } |
| |
| BufferProducer::BufferProducer(const std::string& name, int user_id, |
| int group_id, uint32_t width, uint32_t height, |
| uint32_t format, uint32_t usage, |
| size_t meta_size_bytes) |
| : BufferProducer(name, user_id, group_id, width, height, format, usage, |
| usage, meta_size_bytes) {} |
| |
| BufferProducer::BufferProducer(const std::string& name, int user_id, |
| int group_id, uint32_t width, uint32_t height, |
| uint32_t format, uint64_t producer_usage, |
| uint64_t consumer_usage, size_t meta_size_bytes) |
| : BASE(BufferHubRPC::kClientPath) { |
| ATRACE_NAME("BufferProducer::BufferProducer"); |
| ALOGD_IF(TRACE, |
| "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d " |
| "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64 |
| " consumer_usage=%" PRIx64 " meta_size_bytes=%zu", |
| event_fd(), name.c_str(), user_id, group_id, width, height, format, |
| producer_usage, consumer_usage, meta_size_bytes); |
| |
| // (b/37881101) Deprecate producer/consumer usage |
| auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( |
| name, user_id, group_id, width, height, format, |
| (producer_usage | consumer_usage), meta_size_bytes); |
| if (!status) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to create/get persistent " |
| "buffer \"%s\": %s", |
| name.c_str(), status.GetErrorMessage().c_str()); |
| Close(-status.error()); |
| return; |
| } |
| |
| const int ret = ImportBuffer(); |
| if (ret < 0) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to import producer buffer " |
| "\"%s\": %s", |
| name.c_str(), strerror(-ret)); |
| Close(ret); |
| } |
| } |
| |
| BufferProducer::BufferProducer(uint32_t usage, size_t size) |
| : BufferProducer(usage, usage, size) {} |
| |
| BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, |
| size_t size) |
| : BASE(BufferHubRPC::kClientPath) { |
| ATRACE_NAME("BufferProducer::BufferProducer"); |
| ALOGD_IF(TRACE, |
| "BufferProducer::BufferProducer: producer_usage=%" PRIx64 |
| " consumer_usage=%" PRIx64 " size=%zu", |
| producer_usage, consumer_usage, size); |
| const int width = static_cast<int>(size); |
| const int height = 1; |
| const int format = HAL_PIXEL_FORMAT_BLOB; |
| const size_t meta_size_bytes = 0; |
| |
| // (b/37881101) Deprecate producer/consumer usage |
| auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( |
| width, height, format, (producer_usage | consumer_usage), |
| meta_size_bytes); |
| if (!status) { |
| ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s", |
| status.GetErrorMessage().c_str()); |
| Close(-status.error()); |
| return; |
| } |
| |
| const int ret = ImportBuffer(); |
| if (ret < 0) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to import producer buffer: %s", |
| strerror(-ret)); |
| Close(ret); |
| } |
| } |
| |
| BufferProducer::BufferProducer(const std::string& name, int user_id, |
| int group_id, uint32_t usage, size_t size) |
| : BufferProducer(name, user_id, group_id, usage, usage, size) {} |
| |
| BufferProducer::BufferProducer(const std::string& name, int user_id, |
| int group_id, uint64_t producer_usage, |
| uint64_t consumer_usage, size_t size) |
| : BASE(BufferHubRPC::kClientPath) { |
| ATRACE_NAME("BufferProducer::BufferProducer"); |
| ALOGD_IF(TRACE, |
| "BufferProducer::BufferProducer: name=%s user_id=%d group=%d " |
| "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " size=%zu", |
| name.c_str(), user_id, group_id, producer_usage, consumer_usage, |
| size); |
| const int width = static_cast<int>(size); |
| const int height = 1; |
| const int format = HAL_PIXEL_FORMAT_BLOB; |
| const size_t meta_size_bytes = 0; |
| |
| // (b/37881101) Deprecate producer/consumer usage |
| auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( |
| name, user_id, group_id, width, height, format, |
| (producer_usage | consumer_usage), meta_size_bytes); |
| if (!status) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to create persistent " |
| "buffer \"%s\": %s", |
| name.c_str(), status.GetErrorMessage().c_str()); |
| Close(-status.error()); |
| return; |
| } |
| |
| const int ret = ImportBuffer(); |
| if (ret < 0) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to import producer buffer " |
| "\"%s\": %s", |
| name.c_str(), strerror(-ret)); |
| Close(ret); |
| } |
| } |
| |
| BufferProducer::BufferProducer(const std::string& name) |
| : BASE(BufferHubRPC::kClientPath) { |
| ATRACE_NAME("BufferProducer::BufferProducer"); |
| ALOGD_IF(TRACE, "BufferProducer::BufferProducer: name=%s", name.c_str()); |
| |
| auto status = InvokeRemoteMethod<BufferHubRPC::GetPersistentBuffer>(name); |
| if (!status) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to get producer buffer by name " |
| "\"%s\": %s", |
| name.c_str(), status.GetErrorMessage().c_str()); |
| Close(-status.error()); |
| return; |
| } |
| |
| const int ret = ImportBuffer(); |
| if (ret < 0) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to import producer buffer " |
| "\"%s\": %s", |
| name.c_str(), strerror(-ret)); |
| Close(ret); |
| } |
| } |
| |
| BufferProducer::BufferProducer(LocalChannelHandle channel) |
| : BASE(std::move(channel)) { |
| const int ret = ImportBuffer(); |
| if (ret < 0) { |
| ALOGE( |
| "BufferProducer::BufferProducer: Failed to import producer buffer: %s", |
| strerror(-ret)); |
| Close(ret); |
| } |
| } |
| |
| int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta, |
| size_t meta_size_bytes) { |
| ATRACE_NAME("BufferProducer::Post"); |
| return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>( |
| BorrowedFence(ready_fence.Borrow()), WrapBuffer(meta, meta_size_bytes))); |
| } |
| |
| int BufferProducer::Gain(LocalHandle* release_fence) { |
| ATRACE_NAME("BufferProducer::Gain"); |
| auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>(); |
| if (!status) |
| return -status.error(); |
| if (release_fence) |
| *release_fence = status.take().take(); |
| return 0; |
| } |
| |
| int BufferProducer::GainAsync() { |
| ATRACE_NAME("BufferProducer::GainAsync"); |
| return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode)); |
| } |
| |
| std::unique_ptr<BufferProducer> BufferProducer::Import( |
| LocalChannelHandle channel) { |
| ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value()); |
| return BufferProducer::Create(std::move(channel)); |
| } |
| |
| std::unique_ptr<BufferProducer> BufferProducer::Import( |
| Status<LocalChannelHandle> status) { |
| return Import(status ? status.take() |
| : LocalChannelHandle{nullptr, -status.error()}); |
| } |
| |
| int BufferProducer::MakePersistent(const std::string& name, int user_id, |
| int group_id) { |
| ATRACE_NAME("BufferProducer::MakePersistent"); |
| return ReturnStatusOrError( |
| InvokeRemoteMethod<BufferHubRPC::ProducerMakePersistent>(name, user_id, |
| group_id)); |
| } |
| |
| int BufferProducer::RemovePersistence() { |
| ATRACE_NAME("BufferProducer::RemovePersistence"); |
| return ReturnStatusOrError( |
| InvokeRemoteMethod<BufferHubRPC::ProducerRemovePersistence>()); |
| } |
| |
| } // namespace dvr |
| } // namespace android |