• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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-Component-Aidl"
19 #include <android-base/logging.h>
20 
21 #include <codec2/aidl/Component.h>
22 #include <codec2/aidl/ComponentStore.h>
23 #include <codec2/aidl/InputBufferManager.h>
24 
25 #ifndef __ANDROID_APEX__
26 #include <FilterWrapper.h>
27 #endif
28 
29 #include <android/binder_auto_utils.h>
30 #include <android/binder_interface_utils.h>
31 #include <utils/Timers.h>
32 
33 #include <C2Debug.h>
34 #include <C2PlatformSupport.h>
35 
36 #include <chrono>
37 #include <thread>
38 
39 namespace aidl {
40 namespace android {
41 namespace hardware {
42 namespace media {
43 namespace c2 {
44 namespace utils {
45 
46 using ::aidl::android::hardware::common::NativeHandle;
47 using ::aidl::android::hardware::media::bufferpool2::IClientManager;
48 using ::ndk::ScopedAStatus;
49 using ::android::MultiAccessUnitInterface;
50 using ::android::MultiAccessUnitHelper;
51 
52 // ComponentListener wrapper
53 struct Component::Listener : public C2Component::Listener {
54 
Listeneraidl::android::hardware::media::c2::utils::Component::Listener55     Listener(const std::shared_ptr<Component>& component) :
56             mComponent(component),
57             mListener(component->mListener) {
58         CHECK(component);
59         CHECK(component->mListener);
60     }
61 
onError_nbaidl::android::hardware::media::c2::utils::Component::Listener62     virtual void onError_nb(
63             std::weak_ptr<C2Component> /* c2component */,
64             uint32_t errorCode) override {
65         std::shared_ptr<IComponentListener> listener = mListener.lock();
66         if (listener) {
67             ScopedAStatus transStatus = listener->onError(Status{Status::OK}, errorCode);
68             if (!transStatus.isOk()) {
69                 LOG(ERROR) << "Component::Listener::onError_nb -- "
70                            << "transaction failed.";
71             }
72         }
73     }
74 
onTripped_nbaidl::android::hardware::media::c2::utils::Component::Listener75     virtual void onTripped_nb(
76             std::weak_ptr<C2Component> /* c2component */,
77             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
78             ) override {
79       std::shared_ptr<IComponentListener> listener = mListener.lock();
80         if (listener) {
81             std::vector<SettingResult> settingResults(c2settingResult.size());
82             size_t ix = 0;
83             for (const std::shared_ptr<C2SettingResult> &c2result :
84                     c2settingResult) {
85                 if (c2result) {
86                     if (!ToAidl(&settingResults[ix++], *c2result)) {
87                         break;
88                     }
89                 }
90             }
91             settingResults.resize(ix);
92             ScopedAStatus transStatus = listener->onTripped(settingResults);
93             if (!transStatus.isOk()) {
94                 LOG(ERROR) << "Component::Listener::onTripped_nb -- "
95                            << "transaction failed.";
96             }
97         }
98     }
99 
onWorkDone_nbaidl::android::hardware::media::c2::utils::Component::Listener100     virtual void onWorkDone_nb(
101             std::weak_ptr<C2Component> /* c2component */,
102             std::list<std::unique_ptr<C2Work>> c2workItems) override {
103         for (const std::unique_ptr<C2Work>& work : c2workItems) {
104             if (work) {
105                 if (work->worklets.empty()
106                         || !work->worklets.back()
107                         || (work->worklets.back()->output.flags &
108                             C2FrameData::FLAG_INCOMPLETE) == 0) {
109                     InputBufferManager::
110                             unregisterFrameData(mListener, work->input);
111                 }
112             }
113         }
114 
115         std::shared_ptr<IComponentListener> listener = mListener.lock();
116         if (listener) {
117             WorkBundle workBundle;
118 
119             std::shared_ptr<Component> strongComponent = mComponent.lock();
120             if (!ToAidl(&workBundle, c2workItems, strongComponent ?
121                     &strongComponent->mBufferPoolSender : nullptr)) {
122                 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
123                            << "received corrupted work items.";
124                 return;
125             }
126             ScopedAStatus transStatus = listener->onWorkDone(workBundle);
127             if (!transStatus.isOk()) {
128                 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
129                            << "transaction failed.";
130                 return;
131             }
132             // If output blocks are originally owned by the client(not by HAL),
133             // return the ownership to the client. (Since the blocks are
134             // transferred to the client here.)
135             ReturnOutputBlocksToClientIfNeeded(c2workItems);
136         }
137     }
138 
139 protected:
140     std::weak_ptr<Component> mComponent;
141     std::weak_ptr<IComponentListener> mListener;
142 };
143 
144 // Component listener for handle multiple access-units
145 struct MultiAccessUnitListener : public Component::Listener {
MultiAccessUnitListeneraidl::android::hardware::media::c2::utils::MultiAccessUnitListener146     MultiAccessUnitListener(const std::shared_ptr<Component>& component,
147             const std::shared_ptr<MultiAccessUnitHelper> &helper):
148         Listener(component), mHelper(helper) {
149     }
150 
onError_nbaidl::android::hardware::media::c2::utils::MultiAccessUnitListener151     virtual void onError_nb(
152             std::weak_ptr<C2Component> c2component,
153             uint32_t errorCode) override {
154         if (mHelper) {
155             std::list<std::unique_ptr<C2Work>> worklist;
156             mHelper->error(&worklist);
157             if (!worklist.empty()) {
158                 Listener::onWorkDone_nb(c2component, std::move(worklist));
159             }
160         }
161         Listener::onError_nb(c2component, errorCode);
162     }
163 
onTripped_nbaidl::android::hardware::media::c2::utils::MultiAccessUnitListener164     virtual void onTripped_nb(
165             std::weak_ptr<C2Component> c2component,
166             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
167             ) override {
168         Listener::onTripped_nb(c2component,
169                 c2settingResult);
170     }
171 
onWorkDone_nbaidl::android::hardware::media::c2::utils::MultiAccessUnitListener172     virtual void onWorkDone_nb(
173             std::weak_ptr<C2Component> c2component,
174             std::list<std::unique_ptr<C2Work>> c2workItems) override {
175         if (mHelper) {
176             std::list<std::unique_ptr<C2Work>> processedWork;
177             mHelper->gather(c2workItems, &processedWork);
178             if (!processedWork.empty()) {
179                 Listener::onWorkDone_nb(c2component, std::move(processedWork));
180             }
181         } else {
182             Listener::onWorkDone_nb(c2component, std::move(c2workItems));
183         }
184     }
185 
186     protected:
187         std::shared_ptr<MultiAccessUnitHelper> mHelper;
188 };
189 
190 // Component::DeathContext
191 struct Component::DeathContext {
192     std::weak_ptr<Component> mWeakComp;
193 };
194 
195 // Component
Component(const std::shared_ptr<C2Component> & component,const std::shared_ptr<IComponentListener> & listener,const std::shared_ptr<ComponentStore> & store,const std::shared_ptr<IClientManager> & clientPoolManager)196 Component::Component(
197         const std::shared_ptr<C2Component>& component,
198         const std::shared_ptr<IComponentListener>& listener,
199         const std::shared_ptr<ComponentStore>& store,
200         const std::shared_ptr<IClientManager>& clientPoolManager)
201       : mComponent{component},
202         mListener{listener},
203         mStore{store},
204         mBufferPoolSender{clientPoolManager},
205         mDeathContext(nullptr) {
206     // Retrieve supported parameters from store
207     // TODO: We could cache this per component/interface type
208     mMultiAccessUnitIntf = store->tryCreateMultiAccessUnitInterface(component->intf());
209     mInterface = SharedRefBase::make<ComponentInterface>(
210             component->intf(), mMultiAccessUnitIntf, store->getParameterCache());
211     mInit = mInterface->status();
212 }
213 
status() const214 c2_status_t Component::status() const {
215     return mInit;
216 }
217 
218 // Methods from ::android::hardware::media::c2::V1_1::IComponent
queue(const WorkBundle & workBundle)219 ScopedAStatus Component::queue(const WorkBundle& workBundle) {
220     std::list<std::unique_ptr<C2Work>> c2works;
221 
222     if (!FromAidl(&c2works, workBundle)) {
223         return ScopedAStatus::fromServiceSpecificError(Status::CORRUPTED);
224     }
225 
226     // Register input buffers.
227     for (const std::unique_ptr<C2Work>& work : c2works) {
228         if (work) {
229             InputBufferManager::
230                     registerFrameData(mListener, work->input);
231         }
232     }
233     c2_status_t err = C2_OK;
234     if (mMultiAccessUnitHelper) {
235         std::list<std::list<std::unique_ptr<C2Work>>> c2worklists;
236         mMultiAccessUnitHelper->scatter(c2works, &c2worklists);
237         for (auto &c2worklist : c2worklists) {
238             err = mComponent->queue_nb(&c2worklist);
239             if (err != C2_OK) {
240                 LOG(ERROR) << "Error Queuing to component.";
241                 return ScopedAStatus::fromServiceSpecificError(err);
242             }
243         }
244         return ScopedAStatus::ok();
245     }
246 
247     err = mComponent->queue_nb(&c2works);
248     if (err == C2_OK) {
249         return ScopedAStatus::ok();
250     }
251     return ScopedAStatus::fromServiceSpecificError(err);
252 }
253 
flush(WorkBundle * flushedWorkBundle)254 ScopedAStatus Component::flush(WorkBundle *flushedWorkBundle) {
255     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
256     c2_status_t c2res = mComponent->flush_sm(
257             C2Component::FLUSH_COMPONENT,
258             &c2flushedWorks);
259     if (mMultiAccessUnitHelper) {
260         c2res = mMultiAccessUnitHelper->flush(&c2flushedWorks);
261     }
262     // Unregister input buffers.
263     for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
264         if (work) {
265             if (work->worklets.empty()
266                     || !work->worklets.back()
267                     || (work->worklets.back()->output.flags &
268                         C2FrameData::FLAG_INCOMPLETE) == 0) {
269                 InputBufferManager::
270                         unregisterFrameData(mListener, work->input);
271             }
272         }
273     }
274 
275     if (c2res == C2_OK) {
276         if (!ToAidl(flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
277             c2res = C2_CORRUPTED;
278         }
279     }
280     // If output blocks are originally owned by the client(not by HAL),
281     // return the ownership to the client. (Since the blocks are
282     // transferred to the client here.)
283     ReturnOutputBlocksToClientIfNeeded(c2flushedWorks);
284     if (c2res == C2_OK) {
285         return ScopedAStatus::ok();
286     }
287     return ScopedAStatus::fromServiceSpecificError(c2res);
288 }
289 
drain(bool withEos)290 ScopedAStatus Component::drain(bool withEos) {
291     c2_status_t res = mComponent->drain_nb(withEos ?
292             C2Component::DRAIN_COMPONENT_WITH_EOS :
293             C2Component::DRAIN_COMPONENT_NO_EOS);
294     if (res == C2_OK) {
295         return ScopedAStatus::ok();
296     }
297     return ScopedAStatus::fromServiceSpecificError(res);
298 }
299 
300 namespace /* unnamed */ {
301 
302 struct BlockPoolIntf : public ConfigurableC2Intf {
BlockPoolIntfaidl::android::hardware::media::c2::utils::__anonef82e0e80111::BlockPoolIntf303     BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
304           : ConfigurableC2Intf{
305                 "C2BlockPool:" +
306                     (pool ? std::to_string(pool->getLocalId()) : "null"),
307                 0},
308             mPool{pool} {
309     }
310 
configaidl::android::hardware::media::c2::utils::__anonef82e0e80111::BlockPoolIntf311     virtual c2_status_t config(
312             const std::vector<C2Param*>& params,
313             c2_blocking_t mayBlock,
314             std::vector<std::unique_ptr<C2SettingResult>>* const failures
315             ) override {
316         (void)params;
317         (void)mayBlock;
318         (void)failures;
319         return C2_OK;
320     }
321 
queryaidl::android::hardware::media::c2::utils::__anonef82e0e80111::BlockPoolIntf322     virtual c2_status_t query(
323             const std::vector<C2Param::Index>& indices,
324             c2_blocking_t mayBlock,
325             std::vector<std::unique_ptr<C2Param>>* const params
326             ) const override {
327         (void)indices;
328         (void)mayBlock;
329         (void)params;
330         return C2_OK;
331     }
332 
querySupportedParamsaidl::android::hardware::media::c2::utils::__anonef82e0e80111::BlockPoolIntf333     virtual c2_status_t querySupportedParams(
334             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
335             ) const override {
336         (void)params;
337         return C2_OK;
338     }
339 
querySupportedValuesaidl::android::hardware::media::c2::utils::__anonef82e0e80111::BlockPoolIntf340     virtual c2_status_t querySupportedValues(
341             std::vector<C2FieldSupportedValuesQuery>& fields,
342             c2_blocking_t mayBlock) const override {
343         (void)fields;
344         (void)mayBlock;
345         return C2_OK;
346     }
347 
348 protected:
349     std::shared_ptr<C2BlockPool> mPool;
350 };
351 
352 } // unnamed namespace
353 
createBlockPool(const IComponent::BlockPoolAllocator & allocator,IComponent::BlockPool * blockPool)354 ScopedAStatus Component::createBlockPool(
355         const IComponent::BlockPoolAllocator &allocator,
356         IComponent::BlockPool *blockPool) {
357     std::shared_ptr<C2BlockPool> c2BlockPool;
358     c2_status_t status = C2_OK;
359     ::android::C2PlatformAllocatorDesc allocatorParam;
360     allocatorParam.allocatorId = allocator.allocatorId;
361     switch (allocator.allocatorId) {
362         case ::android::C2PlatformAllocatorStore::IGBA: {
363             allocatorParam.igba = allocator.gbAllocator->igba;
364             allocatorParam.waitableFd.reset(
365                     allocator.gbAllocator->waitableFd.dup().release());
366         }
367         break;
368         default: {
369             // no-op
370         }
371         break;
372     }
373 
374 #ifdef __ANDROID_APEX__
375     status = ::android::CreateCodec2BlockPool(
376             allocatorParam,
377             mComponent,
378             &c2BlockPool);
379 #else
380     status = ComponentStore::GetFilterWrapper()->createBlockPool(
381             allocatorParam,
382             mComponent,
383             &c2BlockPool);
384 #endif
385     if (status != C2_OK) {
386         return ScopedAStatus::fromServiceSpecificError(status);
387     }
388     {
389         mBlockPoolsMutex.lock();
390         mBlockPools.emplace(c2BlockPool->getLocalId(), c2BlockPool);
391         mBlockPoolsMutex.unlock();
392     }
393 
394     blockPool->blockPoolId = c2BlockPool ? c2BlockPool->getLocalId() : 0;
395     blockPool->configurable = SharedRefBase::make<CachedConfigurable>(
396             std::make_unique<BlockPoolIntf>(c2BlockPool));
397     return ScopedAStatus::ok();
398 }
399 
destroyBlockPool(int64_t blockPoolId)400 ScopedAStatus Component::destroyBlockPool(int64_t blockPoolId) {
401     std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
402     if (mBlockPools.erase(blockPoolId) == 1) {
403         return ScopedAStatus::ok();
404     }
405     return ScopedAStatus::fromServiceSpecificError(Status::CORRUPTED);
406 }
407 
start()408 ScopedAStatus Component::start() {
409     c2_status_t status = mComponent->start();
410     if (status == C2_OK) {
411         return ScopedAStatus::ok();
412     }
413     return ScopedAStatus::fromServiceSpecificError(status);
414 }
415 
stop()416 ScopedAStatus Component::stop() {
417     InputBufferManager::unregisterFrameData(mListener);
418     c2_status_t status = mComponent->stop();
419     if (status == C2_OK) {
420         return ScopedAStatus::ok();
421     }
422     return ScopedAStatus::fromServiceSpecificError(status);
423 }
424 
reset()425 ScopedAStatus Component::reset() {
426     c2_status_t status = mComponent->reset();
427     {
428         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
429         mBlockPools.clear();
430     }
431     if (mMultiAccessUnitHelper) {
432         mMultiAccessUnitHelper->reset();
433     }
434     InputBufferManager::unregisterFrameData(mListener);
435     if (status == C2_OK) {
436         return ScopedAStatus::ok();
437     }
438     return ScopedAStatus::fromServiceSpecificError(status);
439 }
440 
release()441 ScopedAStatus Component::release() {
442     c2_status_t status = mComponent->release();
443     {
444         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
445         mBlockPools.clear();
446     }
447     if (mMultiAccessUnitHelper) {
448         mMultiAccessUnitHelper->reset();
449     }
450     InputBufferManager::unregisterFrameData(mListener);
451     if (status == C2_OK) {
452         return ScopedAStatus::ok();
453     }
454     return ScopedAStatus::fromServiceSpecificError(status);
455 }
456 
getInterface(std::shared_ptr<IComponentInterface> * intf)457 ScopedAStatus Component::getInterface(
458         std::shared_ptr<IComponentInterface> *intf) {
459     *intf = mInterface;
460     return ScopedAStatus::ok();
461 }
462 
configureVideoTunnel(int32_t avSyncHwId,NativeHandle * handle)463 ScopedAStatus Component::configureVideoTunnel(
464         int32_t avSyncHwId, NativeHandle *handle) {
465     (void)avSyncHwId;
466     (void)handle;
467     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
468 }
469 
connectToInputSurface(const std::shared_ptr<IInputSurface> & inputSurface,std::shared_ptr<IInputSurfaceConnection> * connection)470 ScopedAStatus Component::connectToInputSurface(
471         const std::shared_ptr<IInputSurface>& inputSurface,
472         std::shared_ptr<IInputSurfaceConnection> *connection) {
473     // TODO
474     (void)inputSurface;
475     (void)connection;
476     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
477 }
478 
asInputSink(std::shared_ptr<IInputSink> * sink)479 ScopedAStatus Component::asInputSink(
480         std::shared_ptr<IInputSink> *sink) {
481     // TODO
482     (void)sink;
483     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
484 }
485 
initListener(const std::shared_ptr<Component> & self)486 void Component::initListener(const std::shared_ptr<Component>& self) {
487     if (__builtin_available(android __ANDROID_API_T__, *)) {
488         std::shared_ptr<C2Component::Listener> c2listener;
489         if (mMultiAccessUnitIntf) {
490             std::shared_ptr<C2Allocator> allocator;
491             std::shared_ptr<C2BlockPool> linearPool;
492             std::shared_ptr<C2AllocatorStore> store = ::android::GetCodec2PlatformAllocatorStore();
493             if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator) == C2_OK) {
494                 ::android::C2PlatformAllocatorDesc desc;
495                 desc.allocatorId = allocator->getId();
496                 if (C2_OK == CreateCodec2BlockPool(desc, mComponent, &linearPool)) {
497                     if (linearPool) {
498                         mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(
499                                 mMultiAccessUnitIntf, linearPool);
500                     }
501                 }
502             }
503         }
504         c2listener = mMultiAccessUnitHelper ?
505                 std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
506                 std::make_shared<Listener>(self);
507         c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
508         if (res != C2_OK) {
509             mInit = res;
510         }
511 
512         // b/321902635, mListener should not be null.
513         CHECK(mListener);
514         mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
515                 AIBinder_DeathRecipient_new(OnBinderDied));
516         mDeathContext = new DeathContext{ref<Component>()};
517         AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), OnBinderUnlinked);
518         AIBinder_linkToDeath(mListener->asBinder().get(), mDeathRecipient.get(), mDeathContext);
519     } else {
520         mInit = C2_NO_INIT;
521     }
522 }
523 
524 // static
OnBinderDied(void * cookie)525 void Component::OnBinderDied(void *cookie) {
526     DeathContext *context = (DeathContext *)cookie;
527     std::shared_ptr<Component> comp = context->mWeakComp.lock();
528     if (comp) {
529         comp->release();
530     }
531 }
532 
533 // static
OnBinderUnlinked(void * cookie)534 void Component::OnBinderUnlinked(void *cookie) {
535     delete (DeathContext *)cookie;
536 }
537 
~Component()538 Component::~Component() {
539     InputBufferManager::unregisterFrameData(mListener);
540     mStore->reportComponentDeath(this);
541     if (mDeathRecipient.get()) {
542         AIBinder_unlinkToDeath(mListener->asBinder().get(), mDeathRecipient.get(), mDeathContext);
543     }
544 }
545 
546 } // namespace utils
547 } // namespace c2
548 } // namespace media
549 } // namespace hardware
550 } // namespace android
551 } // namespace aidl
552