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::__anon3bde3b410111::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::__anon3bde3b410111::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::__anon3bde3b410111::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::__anon3bde3b410111::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::__anon3bde3b410111::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 
157     // Retrieve supported parameters from store
158     using namespace std::placeholders;
159     mInit = mConfigurable->init(mParameterCache);
160 }
161 
~ComponentStore()162 ComponentStore::~ComponentStore() {
163     mParameterCache->onStoreDestroyed();
164 }
165 
status() const166 c2_status_t ComponentStore::status() const {
167     return mInit;
168 }
169 
validateSupportedParams(const std::vector<std::shared_ptr<C2ParamDescriptor>> & params)170 c2_status_t ComponentStore::validateSupportedParams(
171         const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
172     c2_status_t res = C2_OK;
173 
174     for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
175         if (!desc) {
176             // All descriptors should be valid
177             res = res ? res : C2_BAD_VALUE;
178             continue;
179         }
180         C2Param::CoreIndex coreIndex = desc->index().coreIndex();
181         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
182         auto it = mStructDescriptors.find(coreIndex);
183         if (it == mStructDescriptors.end()) {
184             std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
185             if (!structDesc) {
186                 // All supported params must be described
187                 res = C2_BAD_INDEX;
188             }
189             mStructDescriptors.insert({ coreIndex, structDesc });
190         }
191     }
192     return res;
193 }
194 
getParameterCache() const195 std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
196     return mParameterCache;
197 }
198 
199 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
200 // static
GetFilterWrapper()201 std::shared_ptr<FilterWrapper> ComponentStore::GetFilterWrapper() {
202     constexpr const char kPluginPath[] = "libc2filterplugin.so";
203     static std::shared_ptr<FilterWrapper> wrapper = FilterWrapper::Create(
204             std::make_unique<DefaultFilterPlugin>(kPluginPath));
205     return wrapper;
206 }
207 #endif
208 
tryCreateMultiAccessUnitInterface(const std::shared_ptr<C2ComponentInterface> & c2interface)209 std::shared_ptr<MultiAccessUnitInterface> ComponentStore::tryCreateMultiAccessUnitInterface(
210         const std::shared_ptr<C2ComponentInterface> &c2interface) {
211     std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf = nullptr;
212     if (c2interface == nullptr) {
213         return nullptr;
214     }
215     if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
216         c2_status_t err = C2_OK;
217         C2ComponentDomainSetting domain;
218         std::vector<std::unique_ptr<C2Param>> heapParams;
219         err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
220         if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
221             std::vector<std::shared_ptr<C2ParamDescriptor>> params;
222             bool isComponentSupportsLargeAudioFrame = false;
223             c2interface->querySupportedParams_nb(&params);
224             for (const auto &paramDesc : params) {
225                 if (paramDesc->name().compare(C2_PARAMKEY_OUTPUT_LARGE_FRAME) == 0) {
226                     isComponentSupportsLargeAudioFrame = true;
227                     break;
228                 }
229             }
230             if (!isComponentSupportsLargeAudioFrame) {
231                 // TODO - b/342269852: MultiAccessUnitInterface also needs to take multiple
232                 // param reflectors. Currently filters work on video domain only,
233                 // and the MultiAccessUnitHelper is only enabled on audio domain;
234                 // thus we pass the component's param reflector, which is mParamReflectors[0].
235                 multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
236                         c2interface,
237                         std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
238             }
239         }
240     }
241     return multiAccessUnitIntf;
242 }
243 
244 // 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)245 ScopedAStatus ComponentStore::createComponent(
246         const std::string& name,
247         const std::shared_ptr<IComponentListener>& listener,
248         const std::shared_ptr<IClientManager>& pool,
249         std::shared_ptr<IComponent> *component) {
250 
251     if (!listener) {
252         ALOGE("createComponent(): listener is null");
253         return ScopedAStatus::fromServiceSpecificError(Status::BAD_VALUE);
254     }
255     if (!pool) {
256         ALOGE("createComponent(): pool is null");
257         return ScopedAStatus::fromServiceSpecificError(Status::BAD_VALUE);
258     }
259 
260     std::shared_ptr<C2Component> c2component;
261     c2_status_t status =
262             mStore->createComponent(name, &c2component);
263 
264     if (status == C2_OK) {
265 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
266         c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
267 #endif
268         onInterfaceLoaded(c2component->intf());
269         std::shared_ptr<Component> comp =
270             SharedRefBase::make<Component>(c2component, listener, ref<ComponentStore>(), pool);
271         *component = comp;
272         if (!component || !comp) {
273             ALOGE("createComponent(): component cannot be returned");
274             status = C2_CORRUPTED;
275         } else {
276             reportComponentBirth(comp.get());
277             if (comp->status() != C2_OK) {
278                 status = comp->status();
279             } else {
280                 comp->initListener(comp);
281                 if (comp->status() != C2_OK) {
282                     status = comp->status();
283                 }
284             }
285         }
286     }
287     if (status == C2_OK) {
288         return ScopedAStatus::ok();
289     }
290     return ScopedAStatus::fromServiceSpecificError(status);
291 }
292 
createInterface(const std::string & name,std::shared_ptr<IComponentInterface> * intf)293 ScopedAStatus ComponentStore::createInterface(
294         const std::string& name,
295         std::shared_ptr<IComponentInterface> *intf) {
296     std::shared_ptr<C2ComponentInterface> c2interface;
297     c2_status_t res = mStore->createInterface(name, &c2interface);
298     if (res == C2_OK) {
299 #ifndef __ANDROID_APEX__  // Filters are not supported for APEX modules
300         c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
301 #endif
302         onInterfaceLoaded(c2interface);
303         std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf =
304                 tryCreateMultiAccessUnitInterface(c2interface);
305         *intf = SharedRefBase::make<ComponentInterface>(
306                 c2interface, multiAccessUnitIntf, mParameterCache);
307         return ScopedAStatus::ok();
308     }
309     return ScopedAStatus::fromServiceSpecificError(res);
310 }
311 
listComponents(std::vector<IComponentStore::ComponentTraits> * traits)312 ScopedAStatus ComponentStore::listComponents(
313         std::vector<IComponentStore::ComponentTraits> *traits) {
314     std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
315             mStore->listComponents();
316     traits->resize(c2traits.size());
317     size_t ix = 0;
318     for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
319         if (c2trait) {
320             if (ToAidl(&traits->at(ix), *c2trait)) {
321                 ++ix;
322             } else {
323                 break;
324             }
325         }
326     }
327     traits->resize(ix);
328     return ScopedAStatus::ok();
329 }
330 
createInputSurface(std::shared_ptr<IInputSurface> * inputSurface)331 ScopedAStatus ComponentStore::createInputSurface(
332         std::shared_ptr<IInputSurface> *inputSurface) {
333     // TODO
334     (void)inputSurface;
335     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
336 }
337 
onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> & intf)338 void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
339     // invalidate unsupported struct descriptors if a new interface is loaded as it may have
340     // exposed new descriptors
341     std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
342     if (!mLoadedInterfaces.count(intf->getName())) {
343         mUnsupportedStructDescriptors.clear();
344         mLoadedInterfaces.emplace(intf->getName());
345     }
346 }
347 
getStructDescriptors(const std::vector<int32_t> & indices,std::vector<StructDescriptor> * descriptors)348 ScopedAStatus ComponentStore::getStructDescriptors(
349         const std::vector<int32_t>& indices,
350         std::vector<StructDescriptor> *descriptors) {
351     descriptors->resize(indices.size());
352     size_t dstIx = 0;
353     int32_t res = Status::OK;
354     for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
355         std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
356         const C2Param::CoreIndex coreIndex =
357             C2Param::CoreIndex(uint32_t(indices[srcIx])).coreIndex();
358         const auto item = mStructDescriptors.find(coreIndex);
359         if (item == mStructDescriptors.end()) {
360             // not in the cache, and not known to be unsupported, query local reflector
361             if (!mUnsupportedStructDescriptors.count(coreIndex)) {
362                 std::shared_ptr<C2StructDescriptor> structDesc = describe(coreIndex);
363                 if (!structDesc) {
364                     mUnsupportedStructDescriptors.emplace(coreIndex);
365                 } else {
366                     mStructDescriptors.insert({ coreIndex, structDesc });
367                     if (ToAidl(&descriptors->at(dstIx), *structDesc)) {
368                         ++dstIx;
369                         continue;
370                     }
371                     res = Status::CORRUPTED;
372                     break;
373                 }
374             }
375             res = Status::NOT_FOUND;
376         } else if (item->second) {
377             if (ToAidl(&descriptors->at(dstIx), *item->second)) {
378                 ++dstIx;
379                 continue;
380             }
381             res = Status::CORRUPTED;
382             break;
383         } else {
384             res = Status::NO_MEMORY;
385             break;
386         }
387     }
388     descriptors->resize(dstIx);
389     if (res == Status::OK) {
390         return ScopedAStatus::ok();
391     }
392     return ScopedAStatus::fromServiceSpecificError(res);
393 }
394 
getPoolClientManager(std::shared_ptr<IClientManager> * manager)395 ScopedAStatus ComponentStore::getPoolClientManager(
396         std::shared_ptr<IClientManager> *manager) {
397     using ::aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
398     *manager = ClientManager::getInstance();
399     return ScopedAStatus::ok();
400 }
401 
copyBuffer(const Buffer & src,const Buffer & dst)402 ScopedAStatus ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
403     // TODO implement
404     (void)src;
405     (void)dst;
406     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
407 }
408 
getConfigurable(std::shared_ptr<IConfigurable> * configurable)409 ScopedAStatus ComponentStore::getConfigurable(
410         std::shared_ptr<IConfigurable> *configurable) {
411     *configurable = mConfigurable;
412     return ScopedAStatus::ok();
413 }
414 
describe(const C2Param::CoreIndex & index)415 std::shared_ptr<C2StructDescriptor> ComponentStore::describe(const C2Param::CoreIndex &index) {
416     for (const std::shared_ptr<C2ParamReflector> &reflector : mParamReflectors) {
417         std::shared_ptr<C2StructDescriptor> desc = reflector->describe(index);
418         if (desc) {
419             return desc;
420         }
421     }
422     return nullptr;
423 }
424 
425 // Called from createComponent() after a successful creation of `component`.
reportComponentBirth(Component * component)426 void ComponentStore::reportComponentBirth(Component* component) {
427     ComponentStatus componentStatus;
428     componentStatus.c2Component = component->mComponent;
429     componentStatus.birthTime = std::chrono::system_clock::now();
430 
431     std::lock_guard<std::mutex> lock(mComponentRosterMutex);
432     mComponentRoster.emplace(component, componentStatus);
433 }
434 
435 // Called from within the destructor of `component`. No virtual function calls
436 // are made on `component` here.
reportComponentDeath(Component * component)437 void ComponentStore::reportComponentDeath(Component* component) {
438     std::lock_guard<std::mutex> lock(mComponentRosterMutex);
439     mComponentRoster.erase(component);
440 }
441 
442 // Dumps component traits.
dump(std::ostream & out,const std::shared_ptr<const C2Component::Traits> & comp)443 std::ostream& ComponentStore::dump(
444         std::ostream& out,
445         const std::shared_ptr<const C2Component::Traits>& comp) {
446 
447     constexpr const char indent[] = "    ";
448 
449     out << indent << "name: " << comp->name << std::endl;
450     out << indent << "domain: " << comp->domain << std::endl;
451     out << indent << "kind: " << comp->kind << std::endl;
452     out << indent << "rank: " << comp->rank << std::endl;
453     out << indent << "mediaType: " << comp->mediaType << std::endl;
454     out << indent << "aliases:";
455     for (const auto& alias : comp->aliases) {
456         out << ' ' << alias;
457     }
458     out << std::endl;
459 
460     return out;
461 }
462 
463 // Dumps component status.
dump(std::ostream & out,ComponentStatus & compStatus)464 std::ostream& ComponentStore::dump(
465         std::ostream& out,
466         ComponentStatus& compStatus) {
467 
468     constexpr const char indent[] = "    ";
469 
470     // Print birth time.
471     std::chrono::milliseconds ms =
472             std::chrono::duration_cast<std::chrono::milliseconds>(
473                 compStatus.birthTime.time_since_epoch());
474     std::time_t birthTime = std::chrono::system_clock::to_time_t(
475             compStatus.birthTime);
476     std::tm tm = *std::localtime(&birthTime);
477     out << indent << "Creation time: "
478         << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
479         << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
480         << std::endl;
481 
482     // Print name and id.
483     std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
484     if (!intf) {
485         out << indent << "Unknown component -- null interface" << std::endl;
486         return out;
487     }
488     out << indent << "Name: " << intf->getName() << std::endl;
489     out << indent << "Id: " << intf->getId() << std::endl;
490 
491     return out;
492 }
493 
494 // Dumps information when lshal is called.
dump(int fd,const char ** args,uint32_t numArgs)495 binder_status_t ComponentStore::dump(
496         int fd, [[maybe_unused]] const char** args, [[maybe_unused]] uint32_t numArgs) {
497     LOG(INFO) << "debug -- dumping...";
498     std::ostringstream out;
499 
500     { // Populate "out".
501 
502         constexpr const char indent[] = "  ";
503 
504         // Show name.
505         out << "Beginning of dump -- C2ComponentStore: "
506                 << mStore->getName() << std::endl << std::endl;
507 
508         // Retrieve the list of supported components.
509         std::vector<std::shared_ptr<const C2Component::Traits>> traitsList =
510                 mStore->listComponents();
511 
512         // Dump the traits of supported components.
513         out << indent << "Supported components:" << std::endl << std::endl;
514         if (traitsList.size() == 0) {
515             out << indent << indent << "NONE" << std::endl << std::endl;
516         } else {
517             for (const auto& traits : traitsList) {
518                 dump(out, traits) << std::endl;
519             }
520         }
521 
522         // Dump active components.
523         {
524             out << indent << "Active components:" << std::endl << std::endl;
525             std::lock_guard<std::mutex> lock(mComponentRosterMutex);
526             if (mComponentRoster.size() == 0) {
527                 out << indent << indent << "NONE" << std::endl << std::endl;
528             } else {
529                 for (auto& pair : mComponentRoster) {
530                     dump(out, pair.second) << std::endl;
531                 }
532             }
533         }
534 
535         out << "End of dump -- C2ComponentStore: "
536                 << mStore->getName() << std::endl;
537     }
538 
539     if (!::android::base::WriteStringToFd(out.str(), fd)) {
540         PLOG(WARNING) << "debug -- dumping failed -- write()";
541     } else {
542         LOG(INFO) << "debug -- dumping succeeded";
543     }
544     return STATUS_OK;
545 }
546 
547 } // namespace utils
548 } // namespace c2
549 } // namespace media
550 } // namespace hardware
551 } // namespace android
552 } // namespace aidl
553