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