1 #include <poll.h>
2 #include <sys/epoll.h>
3
4 #include <pdx/default_transport/client_channel.h>
5 #include <pdx/default_transport/client_channel_factory.h>
6 #include <private/dvr/buffer_hub_base.h>
7
8 using android::pdx::LocalChannelHandle;
9 using android::pdx::LocalHandle;
10 using android::pdx::Status;
11 using android::pdx::default_transport::ClientChannel;
12 using android::pdx::default_transport::ClientChannelFactory;
13
14 namespace android {
15 namespace dvr {
16
BufferHubBase(LocalChannelHandle channel_handle)17 BufferHubBase::BufferHubBase(LocalChannelHandle channel_handle)
18 : Client{pdx::default_transport::ClientChannel::Create(
19 std::move(channel_handle))},
20 id_(-1),
21 cid_(-1) {}
BufferHubBase(const std::string & endpoint_path)22 BufferHubBase::BufferHubBase(const std::string& endpoint_path)
23 : Client{pdx::default_transport::ClientChannelFactory::Create(
24 endpoint_path)},
25 id_(-1),
26 cid_(-1) {}
27
~BufferHubBase()28 BufferHubBase::~BufferHubBase() {
29 // buffer_state and fence_state are not reset here. They will be used to
30 // clean up epoll fd if necessary in ProducerChannel::RemoveConsumer method.
31 if (metadata_header_ != nullptr) {
32 metadata_buffer_.Unlock();
33 }
34 }
35
CreateConsumer()36 Status<LocalChannelHandle> BufferHubBase::CreateConsumer() {
37 Status<LocalChannelHandle> status =
38 InvokeRemoteMethod<BufferHubRPC::NewConsumer>();
39 ALOGE_IF(!status,
40 "BufferHub::CreateConsumer: Failed to create consumer channel: %s",
41 status.GetErrorMessage().c_str());
42 return status;
43 }
44
ImportBuffer()45 int BufferHubBase::ImportBuffer() {
46 ATRACE_NAME("BufferHubBase::ImportBuffer");
47
48 Status<BufferDescription<LocalHandle>> status =
49 InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
50 if (!status) {
51 ALOGE("BufferHubBase::ImportBuffer: Failed to get buffer: %s",
52 status.GetErrorMessage().c_str());
53 return -status.error();
54 } else if (status.get().id() < 0) {
55 ALOGE("BufferHubBase::ImportBuffer: Received an invalid id!");
56 return -EIO;
57 }
58
59 auto buffer_desc = status.take();
60
61 // Stash the buffer id to replace the value in id_.
62 const int new_id = buffer_desc.id();
63
64 // Import the buffer.
65 IonBuffer ion_buffer;
66 ALOGD_IF(TRACE, "BufferHubBase::ImportBuffer: id=%d.", buffer_desc.id());
67
68 if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
69 return ret;
70
71 // Import the metadata.
72 IonBuffer metadata_buffer;
73 if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
74 ALOGE("Failed to import metadata buffer, error=%d", ret);
75 return ret;
76 }
77 size_t metadata_buf_size = metadata_buffer.width();
78 if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
79 ALOGE("BufferHubBase::ImportBuffer: metadata buffer too small: %zu",
80 metadata_buf_size);
81 return -ENOMEM;
82 }
83
84 // If all imports succee, replace the previous buffer and id.
85 buffer_ = std::move(ion_buffer);
86 metadata_buffer_ = std::move(metadata_buffer);
87 metadata_buf_size_ = metadata_buf_size;
88 user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
89
90 void* metadata_ptr = nullptr;
91 if (const int ret =
92 metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
93 /*y=*/0, metadata_buf_size_,
94 /*height=*/1, &metadata_ptr)) {
95 ALOGE("BufferHubBase::ImportBuffer: Failed to lock metadata.");
96 return ret;
97 }
98
99 // Set up shared fences.
100 shared_acquire_fence_ = buffer_desc.take_acquire_fence();
101 shared_release_fence_ = buffer_desc.take_release_fence();
102 if (!shared_acquire_fence_ || !shared_release_fence_) {
103 ALOGE("BufferHubBase::ImportBuffer: Failed to import shared fences.");
104 return -EIO;
105 }
106
107 metadata_header_ =
108 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
109 if (user_metadata_size_) {
110 user_metadata_ptr_ =
111 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
112 BufferHubDefs::kMetadataHeaderSize);
113 } else {
114 user_metadata_ptr_ = nullptr;
115 }
116
117 id_ = new_id;
118 cid_ = buffer_desc.buffer_cid();
119 client_state_mask_ = buffer_desc.client_state_mask();
120
121 // Note that here the buffer_state, fence_state and active_clients_bit_mask
122 // are mapped from shared memory as an atomic object. The std::atomic's
123 // constructor will not be called so that the original value stored in the
124 // memory region will be preserved.
125 buffer_state_ = &metadata_header_->bufferState;
126 ALOGD_IF(TRACE,
127 "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx32 ".",
128 id(), buffer_state_->load(std::memory_order_acquire));
129 fence_state_ = &metadata_header_->fenceState;
130 ALOGD_IF(TRACE,
131 "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx32 ".", id(),
132 fence_state_->load(std::memory_order_acquire));
133 active_clients_bit_mask_ = &metadata_header_->activeClientsBitMask;
134 ALOGD_IF(
135 TRACE,
136 "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx32
137 ".",
138 id(), active_clients_bit_mask_->load(std::memory_order_acquire));
139
140 return 0;
141 }
142
CheckMetadata(size_t user_metadata_size) const143 int BufferHubBase::CheckMetadata(size_t user_metadata_size) const {
144 if (user_metadata_size && !user_metadata_ptr_) {
145 ALOGE("BufferHubBase::CheckMetadata: doesn't support custom metadata.");
146 return -EINVAL;
147 }
148 if (user_metadata_size > user_metadata_size_) {
149 ALOGE("BufferHubBase::CheckMetadata: too big: %zu, maximum: %zu.",
150 user_metadata_size, user_metadata_size_);
151 return -E2BIG;
152 }
153 return 0;
154 }
155
UpdateSharedFence(const LocalHandle & new_fence,const LocalHandle & shared_fence)156 int BufferHubBase::UpdateSharedFence(const LocalHandle& new_fence,
157 const LocalHandle& shared_fence) {
158 if (pending_fence_fd_.Get() != new_fence.Get()) {
159 // First, replace the old fd if there was already one. Skipping if the new
160 // one is the same as the old.
161 if (pending_fence_fd_.IsValid()) {
162 const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
163 pending_fence_fd_.Get(), nullptr);
164 ALOGW_IF(ret,
165 "BufferHubBase::UpdateSharedFence: failed to remove old fence "
166 "fd from epoll set, error: %s.",
167 strerror(errno));
168 }
169
170 if (new_fence.IsValid()) {
171 // If ready fence is valid, we put that into the epoll set.
172 epoll_event event;
173 event.events = EPOLLIN;
174 event.data.u32 = client_state_mask();
175 pending_fence_fd_ = new_fence.Duplicate();
176 if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
177 &event) < 0) {
178 const int error = errno;
179 ALOGE(
180 "BufferHubBase::UpdateSharedFence: failed to add new fence fd "
181 "into epoll set, error: %s.",
182 strerror(error));
183 return -error;
184 }
185 // Set bit in fence state to indicate that there is a fence from this
186 // producer or consumer.
187 fence_state_->fetch_or(client_state_mask());
188 } else {
189 // Unset bit in fence state to indicate that there is no fence, so that
190 // when consumer to acquire or producer to acquire, it knows no need to
191 // check fence for this buffer.
192 fence_state_->fetch_and(~client_state_mask());
193 }
194 }
195
196 return 0;
197 }
198
Lock(int usage,int x,int y,int width,int height,void ** address)199 int BufferHubBase::Lock(int usage, int x, int y, int width, int height,
200 void** address) {
201 return buffer_.Lock(usage, x, y, width, height, address);
202 }
203
Unlock()204 int BufferHubBase::Unlock() { return buffer_.Unlock(); }
205
GetBlobReadWritePointer(size_t size,void ** addr)206 int BufferHubBase::GetBlobReadWritePointer(size_t size, void** addr) {
207 int width = static_cast<int>(size);
208 int height = 1;
209 int ret = Lock(usage(), 0, 0, width, height, addr);
210 if (ret == 0)
211 Unlock();
212 return ret;
213 }
214
215 } // namespace dvr
216 } // namespace android
217