xref: /aosp_15_r20/frameworks/av/media/codec2/hal/aidl/ComponentStore.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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-ComponentStore-Aidl"
19 #include <android-base/logging.h>
20 
21 #include <bufferpool2/ClientManager.h>
22 #include <codec2/aidl/Component.h>
23 #include <codec2/aidl/ComponentInterface.h>
24 #include <codec2/aidl/ComponentStore.h>
25 #include <codec2/aidl/ParamTypes.h>
26 
27 #include <android-base/file.h>
28 #include <utils/Errors.h>
29 
30 #include <C2PlatformSupport.h>
31 #include <util/C2InterfaceHelper.h>
32 
33 #include <chrono>
34 #include <ctime>
35 #include <iomanip>
36 #include <ostream>
37 #include <sstream>
38 
39 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
40 #include <codec2/hidl/plugin/FilterPlugin.h>
41 #include <dlfcn.h>
42 #include <C2Config.h>
43 #include <DefaultFilterPlugin.h>
44 #include <FilterWrapper.h>
45 #endif
46 
47 namespace aidl {
48 namespace android {
49 namespace hardware {
50 namespace media {
51 namespace c2 {
52 namespace utils {
53 
54 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
55 using ::android::DefaultFilterPlugin;
56 using ::android::FilterWrapper;
57 #endif
58 
59 using ::ndk::ScopedAStatus;
60 
61 namespace /* unnamed */ {
62 
63 struct StoreIntf : public ConfigurableC2Intf {
StoreIntfaidl::android::hardware::media::c2::utils::__anon85522af70111::StoreIntf64     StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
65           : ConfigurableC2Intf{store ? store->getName() : "", 0},
66             mStore{store} {
67     }
68 
configaidl::android::hardware::media::c2::utils::__anon85522af70111::StoreIntf69     virtual c2_status_t config(
70             const std::vector<C2Param*> &params,
71             c2_blocking_t mayBlock,
72             std::vector<std::unique_ptr<C2SettingResult>> *const failures
73             ) override {
74         // Assume all params are blocking
75         // TODO: Filter for supported params
76         if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
77             return C2_BLOCKING;
78         }
79         return mStore->config_sm(params, failures);
80     }
81 
queryaidl::android::hardware::media::c2::utils::__anon85522af70111::StoreIntf82     virtual c2_status_t query(
83             const std::vector<C2Param::Index> &indices,
84             c2_blocking_t mayBlock,
85             std::vector<std::unique_ptr<C2Param>> *const params) const override {
86         // Assume all params are blocking
87         // TODO: Filter for supported params
88         if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
89             return C2_BLOCKING;
90         }
91         return mStore->query_sm({}, indices, params);
92     }
93 
querySupportedParamsaidl::android::hardware::media::c2::utils::__anon85522af70111::StoreIntf94     virtual c2_status_t querySupportedParams(
95             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
96             ) const override {
97         return mStore->querySupportedParams_nb(params);
98     }
99 
querySupportedValuesaidl::android::hardware::media::c2::utils::__anon85522af70111::StoreIntf100     virtual c2_status_t querySupportedValues(
101             std::vector<C2FieldSupportedValuesQuery> &fields,
102             c2_blocking_t mayBlock) const override {
103         // Assume all params are blocking
104         // TODO: Filter for supported params
105         if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
106             return C2_BLOCKING;
107         }
108         return mStore->querySupportedValues_sm(fields);
109     }
110 
111 protected:
112     std::shared_ptr<C2ComponentStore> mStore;
113 };
114 
115 } // unnamed namespace
116 
117 struct ComponentStore::StoreParameterCache : public ParameterCache {
118     std::mutex mStoreMutex;
119     ComponentStore* mStore;
120 
StoreParameterCacheaidl::android::hardware::media::c2::utils::ComponentStore::StoreParameterCache121     StoreParameterCache(ComponentStore* store): mStore{store} {
122     }
123 
validateaidl::android::hardware::media::c2::utils::ComponentStore::StoreParameterCache124     virtual c2_status_t validate(
125             const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
126             ) override {
127         std::scoped_lock _lock(mStoreMutex);
128         return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
129     }
130 
onStoreDestroyedaidl::android::hardware::media::c2::utils::ComponentStore::StoreParameterCache131     void onStoreDestroyed() {
132         std::scoped_lock _lock(mStoreMutex);
133         mStore = nullptr;
134     }
135 };
136 
ComponentStore(const std::shared_ptr<C2ComponentStore> & store)137 ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
138       : mConfigurable{SharedRefBase::make<CachedConfigurable>(std::make_unique<StoreIntf>(store))},
139         mParameterCache{std::make_shared<StoreParameterCache>(this)},
140         mStore{store} {
141 
142     std::shared_ptr<C2ComponentStore> platformStore =
143         ::android::GetCodec2PlatformComponentStore();
144     ::android::SetPreferredCodec2ComponentStore(store);
145 
146     // Retrieve struct descriptors
147     mParamReflectors.push_back(mStore->getParamReflector());
148 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
149     std::shared_ptr<C2ParamReflector> paramReflector =
150         GetFilterWrapper()->getParamReflector();
151     if (paramReflector != nullptr) {
152         ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
153         mParamReflectors.push_back(paramReflector);
154     }
155 #endif
156     // MultiAccessUnit reflector helper is allocated once per store.
157     // All components in this store can reuse this reflector helper.
158     if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
159         std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
160         mParamReflectors.push_back(helper);
161         mMultiAccessUnitReflector = helper;
162     }
163 
164     // Retrieve supported parameters from store
165     using namespace std::placeholders;
166     mInit = mConfigurable->init(mParameterCache);
167 }
168 
~ComponentStore()169 ComponentStore::~ComponentStore() {
170     mParameterCache->onStoreDestroyed();
171 }
172 
status() const173 c2_status_t ComponentStore::status() const {
174     return mInit;
175 }
176 
validateSupportedParams(const std::vector<std::shared_ptr<C2ParamDescriptor>> & params)177 c2_status_t ComponentStore::validateSupportedParams(
178         const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
179     c2_status_t res = C2_OK;
180 
181     for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
182         if (!desc) {
183             // All descriptors should be valid
184             res = res ? res : C2_BAD_VALUE;
185             continue;
186         }
187         C2Param::CoreIndex coreIndex = desc->index().coreIndex();
188         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
189         auto it = mStructDescriptors.find(coreIndex);
190         if (it == mStructDescriptors.end()) {
191             std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
192             if (!structDesc) {
193                 // All supported params must be described
194                 res = C2_BAD_INDEX;
195             }
196             mStructDescriptors.insert({ coreIndex, structDesc });
197         }
198     }
199     return res;
200 }
201 
getParameterCache() const202 std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
203     return mParameterCache;
204 }
205 
206 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
207 // static
GetFilterWrapper()208 std::shared_ptr<FilterWrapper> ComponentStore::GetFilterWrapper() {
209     constexpr const char kPluginPath[] = "libc2filterplugin.so";
210     static std::shared_ptr<FilterWrapper> wrapper = FilterWrapper::Create(
211             std::make_unique<DefaultFilterPlugin>(kPluginPath));
212     return wrapper;
213 }
214 #endif
215 
tryCreateMultiAccessUnitInterface(const std::shared_ptr<C2ComponentInterface> & c2interface)216 std::shared_ptr<MultiAccessUnitInterface> ComponentStore::tryCreateMultiAccessUnitInterface(
217         const std::shared_ptr<C2ComponentInterface> &c2interface) {
218     std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf = nullptr;
219     if (c2interface == nullptr) {
220         return nullptr;
221     }
222     // Framework support for Large audio frame feature depends on:
223     // 1. All feature flags enabled on platform
224     // 2. The capability of the implementation to use the same input buffer
225     //    for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
226     // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
227     if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
228         c2_status_t err = C2_OK;
229         C2ComponentDomainSetting domain;
230         std::vector<std::unique_ptr<C2Param>> heapParams;
231         C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
232         err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
233         if (err == C2_OK
234                 && (domain.value == C2Component::DOMAIN_AUDIO)
235                 && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
236             std::vector<std::shared_ptr<C2ParamDescriptor>> params;
237             bool isComponentSupportsLargeAudioFrame = false;
238             c2interface->querySupportedParams_nb(&params);
239             for (const auto &paramDesc : params) {
240                 if (paramDesc->name().compare(C2_PARAMKEY_OUTPUT_LARGE_FRAME) == 0) {
241                     isComponentSupportsLargeAudioFrame = true;
242                     break;
243                 }
244             }
245             if (!isComponentSupportsLargeAudioFrame) {
246                 // TODO - b/342269852: MultiAccessUnitInterface also needs to take multiple
247                 // param reflectors. Currently filters work on video domain only,
248                 // and the MultiAccessUnitHelper is only enabled on audio domain;
249                 // thus we pass the component's param reflector, which is mParamReflectors[0].
250                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
251                         c2interface,
252                         mMultiAccessUnitReflector);
253             }
254         }
255     }
256     return multiAccessUnitIntf;
257 }
258 
259 // Methods from ::aidl::android::hardware::media::c2::IComponentStore
createComponent(const std::string & name,const std::shared_ptr<IComponentListener> & listener,const std::shared_ptr<IClientManager> & pool,std::shared_ptr<IComponent> * component)260 ScopedAStatus ComponentStore::createComponent(
261         const std::string& name,
262         const std::shared_ptr<IComponentListener>& listener,
263         const std::shared_ptr<IClientManager>& pool,
264         std::shared_ptr<IComponent> *component) {
265 
266     if (!listener) {
267         ALOGE("createComponent(): listener is null");
268         return ScopedAStatus::fromServiceSpecificError(Status::BAD_VALUE);
269     }
270     if (!pool) {
271         ALOGE("createComponent(): pool is null");
272         return ScopedAStatus::fromServiceSpecificError(Status::BAD_VALUE);
273     }
274 
275     std::shared_ptr<C2Component> c2component;
276     c2_status_t status =
277             mStore->createComponent(name, &c2component);
278 
279     if (status == C2_OK) {
280 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
281         c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
282 #endif
283         onInterfaceLoaded(c2component->intf());
284         std::shared_ptr<Component> comp =
285             SharedRefBase::make<Component>(c2component, listener, ref<ComponentStore>(), pool);
286         *component = comp;
287         if (!component || !comp) {
288             ALOGE("createComponent(): component cannot be returned");
289             status = C2_CORRUPTED;
290         } else {
291             reportComponentBirth(comp.get());
292             if (comp->status() != C2_OK) {
293                 status = comp->status();
294             } else {
295                 comp->initListener(comp);
296                 if (comp->status() != C2_OK) {
297                     status = comp->status();
298                 }
299             }
300         }
301     }
302     if (status == C2_OK) {
303         return ScopedAStatus::ok();
304     }
305     return ScopedAStatus::fromServiceSpecificError(status);
306 }
307 
createInterface(const std::string & name,std::shared_ptr<IComponentInterface> * intf)308 ScopedAStatus ComponentStore::createInterface(
309         const std::string& name,
310         std::shared_ptr<IComponentInterface> *intf) {
311     std::shared_ptr<C2ComponentInterface> c2interface;
312     c2_status_t res = mStore->createInterface(name, &c2interface);
313     if (res == C2_OK) {
314 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
315         c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
316 #endif
317         onInterfaceLoaded(c2interface);
318         std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf =
319                 tryCreateMultiAccessUnitInterface(c2interface);
320         *intf = SharedRefBase::make<ComponentInterface>(
321                 c2interface, multiAccessUnitIntf, mParameterCache);
322         return ScopedAStatus::ok();
323     }
324     return ScopedAStatus::fromServiceSpecificError(res);
325 }
326 
listComponents(std::vector<IComponentStore::ComponentTraits> * traits)327 ScopedAStatus ComponentStore::listComponents(
328         std::vector<IComponentStore::ComponentTraits> *traits) {
329     std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
330             mStore->listComponents();
331     traits->resize(c2traits.size());
332     size_t ix = 0;
333     for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
334         if (c2trait) {
335             if (ToAidl(&traits->at(ix), *c2trait)) {
336                 ++ix;
337             } else {
338                 break;
339             }
340         }
341     }
342     traits->resize(ix);
343     return ScopedAStatus::ok();
344 }
345 
createInputSurface(std::shared_ptr<IInputSurface> * inputSurface)346 ScopedAStatus ComponentStore::createInputSurface(
347         std::shared_ptr<IInputSurface> *inputSurface) {
348     // TODO
349     (void)inputSurface;
350     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
351 }
352 
onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> & intf)353 void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
354     // invalidate unsupported struct descriptors if a new interface is loaded as it may have
355     // exposed new descriptors
356     std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
357     if (!mLoadedInterfaces.count(intf->getName())) {
358         mUnsupportedStructDescriptors.clear();
359         mLoadedInterfaces.emplace(intf->getName());
360     }
361 }
362 
getStructDescriptors(const std::vector<int32_t> & indices,std::vector<StructDescriptor> * descriptors)363 ScopedAStatus ComponentStore::getStructDescriptors(
364         const std::vector<int32_t>& indices,
365         std::vector<StructDescriptor> *descriptors) {
366     descriptors->resize(indices.size());
367     size_t dstIx = 0;
368     int32_t res = Status::OK;
369     for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
370         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
371         const C2Param::CoreIndex coreIndex =
372             C2Param::CoreIndex(uint32_t(indices[srcIx])).coreIndex();
373         const auto item = mStructDescriptors.find(coreIndex);
374         if (item == mStructDescriptors.end()) {
375             // not in the cache, and not known to be unsupported, query local reflector
376             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
377                 std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
378                 if (!structDesc) {
379                     mUnsupportedStructDescriptors.emplace(coreIndex);
380                 } else {
381                     mStructDescriptors.insert({ coreIndex, structDesc });
382                     if (ToAidl(&descriptors->at(dstIx), *structDesc)) {
383                         ++dstIx;
384                         continue;
385                     }
386                     res = Status::CORRUPTED;
387                     break;
388                 }
389             }
390             res = Status::NOT_FOUND;
391         } else if (item->second) {
392             if (ToAidl(&descriptors->at(dstIx), *item->second)) {
393                 ++dstIx;
394                 continue;
395             }
396             res = Status::CORRUPTED;
397             break;
398         } else {
399             res = Status::NO_MEMORY;
400             break;
401         }
402     }
403     descriptors->resize(dstIx);
404     if (res == Status::OK) {
405         return ScopedAStatus::ok();
406     }
407     return ScopedAStatus::fromServiceSpecificError(res);
408 }
409 
getPoolClientManager(std::shared_ptr<IClientManager> * manager)410 ScopedAStatus ComponentStore::getPoolClientManager(
411         std::shared_ptr<IClientManager> *manager) {
412     using ::aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
413     *manager = ClientManager::getInstance();
414     return ScopedAStatus::ok();
415 }
416 
copyBuffer(const Buffer & src,const Buffer & dst)417 ScopedAStatus ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
418     // TODO implement
419     (void)src;
420     (void)dst;
421     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
422 }
423 
getConfigurable(std::shared_ptr<IConfigurable> * configurable)424 ScopedAStatus ComponentStore::getConfigurable(
425         std::shared_ptr<IConfigurable> *configurable) {
426     *configurable = mConfigurable;
427     return ScopedAStatus::ok();
428 }
429 
describe(const C2Param::CoreIndex & index)430 std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
431     for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
432         std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
433         if (desc) {
434             return desc;
435         }
436     }
437     return nullptr;
438 }
439 
440 // Called from createComponent() after a successful creation of `component`.
reportComponentBirth(Component * component)441 void ComponentStore::reportComponentBirth(Component* component) {
442     ComponentStatus componentStatus;
443     componentStatus.c2Component = component->mComponent;
444     componentStatus.birthTime = std::chrono::system_clock::now();
445 
446     std::lock_guard<std::mutex> lock(mComponentRosterMutex);
447     mComponentRoster.emplace(component, componentStatus);
448 }
449 
450 // Called from within the destructor of `component`. No virtual function calls
451 // are made on `component` here.
reportComponentDeath(Component * component)452 void ComponentStore::reportComponentDeath(Component* component) {
453     std::lock_guard<std::mutex> lock(mComponentRosterMutex);
454     mComponentRoster.erase(component);
455 }
456 
457 // Dumps component traits.
dump(std::ostream & out,const std::shared_ptr<const C2Component::Traits> & comp)458 std::ostream& ComponentStore::dump(
459         std::ostream& out,
460         const std::shared_ptr<const C2Component::Traits>& comp) {
461 
462     constexpr const char indent[] = "    ";
463 
464     out << indent << "name: " << comp->name << std::endl;
465     out << indent << "domain: " << comp->domain << std::endl;
466     out << indent << "kind: " << comp->kind << std::endl;
467     out << indent << "rank: " << comp->rank << std::endl;
468     out << indent << "mediaType: " << comp->mediaType << std::endl;
469     out << indent << "aliases:";
470     for (const auto& alias : comp->aliases) {
471         out << ' ' << alias;
472     }
473     out << std::endl;
474 
475     return out;
476 }
477 
478 // Dumps component status.
dump(std::ostream & out,ComponentStatus & compStatus)479 std::ostream& ComponentStore::dump(
480         std::ostream& out,
481         ComponentStatus& compStatus) {
482 
483     constexpr const char indent[] = "    ";
484 
485     // Print birth time.
486     std::chrono::milliseconds ms =
487             std::chrono::duration_cast<std::chrono::milliseconds>(
488                 compStatus.birthTime.time_since_epoch());
489     std::time_t birthTime = std::chrono::system_clock::to_time_t(
490             compStatus.birthTime);
491     std::tm tm = *std::localtime(&birthTime);
492     out << indent << "Creation time: "
493         << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
494         << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
495         << std::endl;
496 
497     // Print name and id.
498     std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
499     if (!intf) {
500         out << indent << "Unknown component -- null interface" << std::endl;
501         return out;
502     }
503     out << indent << "Name: " << intf->getName() << std::endl;
504     out << indent << "Id: " << intf->getId() << std::endl;
505 
506     return out;
507 }
508 
509 // Dumps information when lshal is called.
dump(int fd,const char ** args,uint32_t numArgs)510 binder_status_t ComponentStore::dump(
511         int fd, [[maybe_unused]] const char** args, [[maybe_unused]] uint32_t numArgs) {
512     LOG(INFO) << "debug -- dumping...";
513     std::ostringstream out;
514 
515     { // Populate "out".
516 
517         constexpr const char indent[] = "  ";
518 
519         // Show name.
520         out << "Beginning of dump -- C2ComponentStore: "
521                 << mStore->getName() << std::endl << std::endl;
522 
523         // Retrieve the list of supported components.
524         std::vector<std::shared_ptr<const C2Component::Traits>> traitsList =
525                 mStore->listComponents();
526 
527         // Dump the traits of supported components.
528         out << indent << "Supported components:" << std::endl << std::endl;
529         if (traitsList.size() == 0) {
530             out << indent << indent << "NONE" << std::endl << std::endl;
531         } else {
532             for (const auto& traits : traitsList) {
533                 dump(out, traits) << std::endl;
534             }
535         }
536 
537         // Dump active components.
538         {
539             out << indent << "Active components:" << std::endl << std::endl;
540             std::lock_guard<std::mutex> lock(mComponentRosterMutex);
541             if (mComponentRoster.size() == 0) {
542                 out << indent << indent << "NONE" << std::endl << std::endl;
543             } else {
544                 for (auto& pair : mComponentRoster) {
545                     dump(out, pair.second) << std::endl;
546                 }
547             }
548         }
549 
550         out << "End of dump -- C2ComponentStore: "
551                 << mStore->getName() << std::endl;
552     }
553 
554     if (!::android::base::WriteStringToFd(out.str(), fd)) {
555         PLOG(WARNING) << "debug -- dumping failed -- write()";
556     } else {
557         LOG(INFO) << "debug -- dumping succeeded";
558     }
559     return STATUS_OK;
560 }
561 
562 } // namespace utils
563 } // namespace c2
564 } // namespace media
565 } // namespace hardware
566 } // namespace android
567 } // namespace aidl
568