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*> ¶ms,
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(¶ms);
239 for (const auto ¶mDesc : 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