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