1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "Codec2-AIDL-BufferTypes"
19 #include <android-base/logging.h>
20 
21 #include <aidlcommonsupport/NativeHandle.h>
22 #include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
23 #include <bufferpool2/BufferPoolTypes.h>
24 #include <codec2/aidl/BufferTypes.h>
25 #include <codec2/common/BufferTypes.h>
26 #include <cutils/native_handle.h>
27 #include <media/stagefright/foundation/AUtils.h>
28 
29 #include <C2AllocatorIon.h>
30 #include <C2AllocatorGralloc.h>
31 #include <C2BlockInternal.h>
32 #include <C2Buffer.h>
33 #include <C2Component.h>
34 #include <C2FenceFactory.h>
35 #include <C2Param.h>
36 #include <C2PlatformSupport.h>
37 #include <C2Work.h>
38 
39 #include <algorithm>
40 #include <functional>
41 #include <iomanip>
42 #include <unordered_map>
43 
44 #include "ParamTypes-specialization.h"
45 
46 namespace android {
47 
48 using ::aidl::android::hardware::media::bufferpool2::BufferPoolData;
49 using ::aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
50 using ::aidl::android::hardware::media::bufferpool2::ResultStatus;
51 using ::aidl::android::hardware::media::bufferpool2::implementation::BufferPoolStatus;
52 using ::aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
53 using ::aidl::android::hardware::media::c2::BaseBlock;
54 using ::aidl::android::hardware::media::c2::utils::BufferPoolTypes;
55 
56 using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle;
57 using AidlHardwareBuffer = ::aidl::android::hardware::HardwareBuffer;
58 
59 constexpr BaseBlock::Tag NATIVE_BLOCK = BaseBlock::nativeBlock;
60 constexpr BaseBlock::Tag HWB_BLOCK = BaseBlock::hwbBlock;
61 constexpr BaseBlock::Tag POOLED_BLOCK = BaseBlock::pooledBlock;
62 
63 // BaseBlock -> C2BaseBlock
64 template<>
objcpy(C2BaseBlock * d,const BaseBlock & s)65 bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
66     switch (s.getTag()) {
67     case NATIVE_BLOCK: {
68             if (isAidlNativeHandleEmpty(s.get<NATIVE_BLOCK>())) {
69                 LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
70                 return false;
71             }
72             native_handle_t* sHandle =
73                     ::android::dupFromAidl(s.get<NATIVE_BLOCK>());
74             if (sHandle == nullptr) {
75                 LOG(ERROR) << "Null BaseBlock::nativeBlock.";
76                 return false;
77             }
78             const C2Handle *sC2Handle =
79                     reinterpret_cast<const C2Handle*>(sHandle);
80 
81             // If successful, the handle is deleted(!) and fds are owned by the block.
82             d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
83             if (d->linear) {
84                 d->type = ::android::C2BaseBlock::LINEAR;
85                 return true;
86             }
87 
88             // If successful, the handle is deleted(!) and fds are owned by the block.
89             d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
90             if (d->graphic) {
91                 d->type = ::android::C2BaseBlock::GRAPHIC;
92                 return true;
93             }
94 
95             LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
96             if (sHandle) {
97                 native_handle_close(sHandle);
98                 native_handle_delete(sHandle);
99             }
100             return false;
101         }
102     case HWB_BLOCK: {
103             AHardwareBuffer *pBuf =
104                     const_cast<AidlHardwareBuffer&>(
105                             s.get<HWB_BLOCK>()).release();
106             d->graphic = _C2BlockFactory::CreateGraphicBlock(pBuf);
107             if (pBuf) {
108                 AHardwareBuffer_release(pBuf);
109             }
110             if (d->graphic) {
111                 d->type = ::android::C2BaseBlock::GRAPHIC;
112                 return true;
113             }
114             LOG(ERROR) << "Improper ahwb in BaseBlock::hwbBlock.";
115             return false;
116         }
117     case POOLED_BLOCK: {
118             const BufferStatusMessage &bpMessage = s.get<POOLED_BLOCK>();
119             std::shared_ptr<ClientManager> bp = ClientManager::getInstance();
120             std::shared_ptr<BufferPoolData> bpData;
121             native_handle_t *cHandle;
122             BufferPoolStatus bpStatus = bp->receive(
123                     bpMessage.connectionId,
124                     bpMessage.transactionId,
125                     bpMessage.bufferId,
126                     bpMessage.timestampUs,
127                     &cHandle,
128                     &bpData);
129             if (bpStatus != ResultStatus::OK) {
130                 LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
131                            << "resultStatus = " << bpStatus << ".";
132                 return false;
133             } else if (!bpData) {
134                 LOG(ERROR) << "No data in bufferpool transaction.";
135                 return false;
136             }
137 
138             // If successful, the handle is deleted(!) and fds are owned by the block.
139             d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
140             if (d->linear) {
141                 d->type = ::android::C2BaseBlock::LINEAR;
142                 return true;
143             }
144 
145             // If successful, the handle is deleted(!) and fds are owned by the block.
146             d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
147             if (d->graphic) {
148                 d->type = ::android::C2BaseBlock::GRAPHIC;
149                 return true;
150             }
151             if (cHandle) {
152                 // Though we got cloned handle, creating block failed.
153                 native_handle_close(cHandle);
154                 native_handle_delete(cHandle);
155             }
156 
157             LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
158             return false;
159         }
160     default:
161         LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
162                    << "underlying value "
163                    << ::android::underlying_value(s.getTag()) << ".";
164         return false;
165     }
166 }
167 
168 // C2Fence -> AidlNativeHandle
169 template<>
objcpy(AidlNativeHandle * d,const C2Fence & s)170 bool objcpy(AidlNativeHandle* d, const C2Fence& s) {
171     // fds are not duplicated here
172     native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
173     if (handle) {
174         // |d| copies the fds without duplicating
175         *d = makeToAidl(handle);
176         // no fds are duplicated, just delete the handle
177         // Note: C2Fence still owns the fds and should not be cleared
178         // before the transaction is complete.
179         native_handle_delete(handle);
180 //  } else if (!s.ready()) {
181 //      // TODO: we should wait for unmarshallable fences but this may not be
182 //      // the best place for it. We can safely ignore here as at this time
183 //      // all fences used here are marshallable.
184     }
185     return true;
186 }
187 
188 // AidlNativeHandle -> C2Fence
189 template<>
objcpy(C2Fence * d,const AidlNativeHandle & s)190 bool objcpy(C2Fence* d, const AidlNativeHandle& s) {
191     // makeFromAidl does not duplicate the fds.
192     native_handle_t* handle = makeFromAidl(s);
193     // C2Fence duplicates and owns the fds
194     *d = _C2FenceFactory::CreateFromNativeHandle(handle);
195     if (handle) {
196         // |handle| should not be closed here, as the fds are owned by |s|
197         native_handle_delete(handle);
198     }
199     return true;
200 }
201 
202 template<>
SetHandle(BaseBlock * block,const C2Handle * handle)203 void SetHandle(BaseBlock *block, const C2Handle *handle) {
204     block->set<BaseBlock::nativeBlock>(dupToAidl(handle));
205 }
206 
207 template<>
SetAHardwareBuffer(BaseBlock * block,AHardwareBuffer * ahwb)208 void SetAHardwareBuffer(BaseBlock *block, AHardwareBuffer *ahwb) {
209     AHardwareBuffer_acquire(ahwb);
210     block->set<HWB_BLOCK>(AidlHardwareBuffer());
211     (block->get<HWB_BLOCK>()).reset(ahwb);
212 }
213 
214 template<>
SetPooledBlock(BaseBlock * baseBlock,const typename BufferPoolTypes::BufferStatusMessage & pooledBlock)215 void SetPooledBlock<BufferPoolTypes>(
216         BaseBlock *baseBlock,
217         const typename BufferPoolTypes::BufferStatusMessage &pooledBlock) {
218     baseBlock->set<POOLED_BLOCK>(pooledBlock);
219 }
220 
221 template<>
GetBufferPoolData(const std::shared_ptr<const _C2BlockPoolData> & blockPoolData,std::shared_ptr<typename BufferPoolTypes::BufferPoolData> * bpData)222 bool GetBufferPoolData<BufferPoolTypes>(
223         const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
224         std::shared_ptr<typename BufferPoolTypes::BufferPoolData> *bpData) {
225     return _C2BlockFactory::GetBufferPoolData(blockPoolData, bpData);
226 }
227 
228 }  // namespace android
229 
230 namespace aidl {
231 namespace android {
232 namespace hardware {
233 namespace media {
234 namespace c2 {
235 namespace utils {
236 
237 namespace bufferpool2 = ::aidl::android::hardware::media::bufferpool2;
238 namespace bufferpool2_impl = ::aidl::android::hardware::media::bufferpool2::implementation;
239 
240 // DefaultBufferPoolSender's implementation
241 
DefaultBufferPoolSender(const std::shared_ptr<IClientManager> & receiverManager,std::chrono::steady_clock::duration refreshInterval)242 DefaultBufferPoolSender::DefaultBufferPoolSender(
243         const std::shared_ptr<IClientManager>& receiverManager,
244         std::chrono::steady_clock::duration refreshInterval)
245     : mReceiverManager(receiverManager),
246       mRefreshInterval(refreshInterval) {
247 }
248 
setReceiver(const std::shared_ptr<IClientManager> & receiverManager,std::chrono::steady_clock::duration refreshInterval)249 void DefaultBufferPoolSender::setReceiver(
250         const std::shared_ptr<IClientManager>& receiverManager,
251         std::chrono::steady_clock::duration refreshInterval) {
252     std::lock_guard<std::mutex> lock(mMutex);
253     if (mReceiverManager != receiverManager) {
254         mReceiverManager = receiverManager;
255         mConnections.clear();
256     }
257     mRefreshInterval = refreshInterval;
258 }
259 
send(const std::shared_ptr<bufferpool2::BufferPoolData> & bpData,bufferpool2::BufferStatusMessage * bpMessage)260 BufferPoolTypes::BufferPoolStatus DefaultBufferPoolSender::send(
261         const std::shared_ptr<bufferpool2::BufferPoolData>& bpData,
262         bufferpool2::BufferStatusMessage* bpMessage) {
263     int64_t connectionId = bpData->mConnectionId;
264     if (connectionId == 0) {
265         LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
266         return bufferpool2::ResultStatus::CRITICAL_ERROR;
267     }
268     std::lock_guard<std::mutex> lock(mMutex);
269     if (!mReceiverManager) {
270         LOG(ERROR) << "No access to receiver's BufferPool.";
271         return bufferpool2::ResultStatus::NOT_FOUND;
272     }
273     if (!mSenderManager) {
274         mSenderManager = ClientManager::getInstance();
275         if (!mSenderManager) {
276             LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
277             return bufferpool2::ResultStatus::CRITICAL_ERROR;
278         }
279     }
280 
281     int64_t receiverConnectionId{0};
282     auto foundConnection = mConnections.find(connectionId);
283     bool isNewConnection = foundConnection == mConnections.end();
284     std::chrono::steady_clock::time_point now =
285             std::chrono::steady_clock::now();
286     if (isNewConnection ||
287             (now - foundConnection->second.lastSent > mRefreshInterval)) {
288         // Initialize the bufferpool connection.
289         bufferpool2_impl::BufferPoolStatus rs =
290                 mSenderManager->registerSender(mReceiverManager,
291                                                connectionId,
292                                                &receiverConnectionId,
293                                                &isNewConnection);
294         if ((rs != bufferpool2::ResultStatus::OK)
295                 && (rs != bufferpool2::ResultStatus::ALREADY_EXISTS)) {
296             LOG(WARNING) << "registerSender -- returned error: "
297                          << static_cast<int32_t>(rs)
298                          << ".";
299             return rs;
300         } else if (receiverConnectionId == 0) {
301             LOG(WARNING) << "registerSender -- "
302                             "invalid receiver connection id (0).";
303             return bufferpool2::ResultStatus::CRITICAL_ERROR;
304         } else {
305             if (foundConnection == mConnections.end()) {
306                 foundConnection = mConnections.try_emplace(
307                         connectionId, receiverConnectionId, now).first;
308             } else {
309                 foundConnection->second.receiverConnectionId = receiverConnectionId;
310             }
311         }
312     } else {
313         receiverConnectionId = foundConnection->second.receiverConnectionId;
314     }
315 
316     uint64_t transactionId;
317     int64_t timestampUs;
318     bufferpool2_impl::BufferPoolStatus rs = mSenderManager->postSend(
319             receiverConnectionId, bpData, &transactionId, &timestampUs);
320     if (rs != bufferpool2::ResultStatus::OK) {
321         LOG(ERROR) << "ClientManager::postSend -- returned error: "
322                    << static_cast<int32_t>(rs)
323                    << ".";
324         mConnections.erase(foundConnection);
325         return rs;
326     }
327     if (!bpMessage) {
328         LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
329         mConnections.erase(foundConnection);
330         return bufferpool2::ResultStatus::CRITICAL_ERROR;
331     }
332     bpMessage->connectionId = receiverConnectionId;
333     bpMessage->bufferId = bpData->mId;
334     bpMessage->transactionId = transactionId;
335     bpMessage->timestampUs = timestampUs;
336     foundConnection->second.lastSent = now;
337     return rs;
338 }
339 
340 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
ToAidl(WorkBundle * d,const std::list<std::unique_ptr<C2Work>> & s,::android::BufferPoolSender<BufferPoolTypes> * bufferPoolSender)341 bool ToAidl(
342         WorkBundle* d,
343         const std::list<std::unique_ptr<C2Work>>& s,
344         ::android::BufferPoolSender<BufferPoolTypes>* bufferPoolSender) {
345     return ::android::objcpy(d, s, bufferPoolSender);
346 }
347 
348 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
FromAidl(std::list<std::unique_ptr<C2Work>> * d,const WorkBundle & s)349 bool FromAidl(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
350     return ::android::objcpy(d, s);
351 }
352 
ReturnOutputBlocksToClientIfNeeded(const std::list<std::unique_ptr<C2Work>> & workList)353 void ReturnOutputBlocksToClientIfNeeded(
354         const std::list<std::unique_ptr<C2Work>>& workList) {
355     for (const std::unique_ptr<C2Work>& work : workList) {
356         if (!work) {
357             continue;
358         }
359         for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
360             if (worklet) {
361                 for (const std::shared_ptr<C2Buffer>& buffer : worklet->output.buffers) {
362                     if (buffer) {
363                         for (const C2ConstGraphicBlock& block : buffer->data().graphicBlocks()) {
364                             std::shared_ptr<_C2BlockPoolData> poolData =
365                                   _C2BlockFactory::GetGraphicBlockPoolData(block);
366                             _C2BlockFactory::DisownIgbaBlock(poolData);
367                         }
368                     }
369                 }
370             }
371         }
372     }
373 }
374 
375 }  // namespace utils
376 }  // namespace c2
377 }  // namespace media
378 }  // namespace hardware
379 }  // namespace android
380 }  // namespace aidl
381 
382