1 /*
2 * Copyright (C) 2017 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_TAG "C2Store"
18 #define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <C2AllocatorGralloc.h>
22 #include <C2AllocatorIon.h>
23 #include <C2BufferPriv.h>
24 #include <C2BqBufferPriv.h>
25 #include <C2Component.h>
26 #include <C2Config.h>
27 #include <C2PlatformStorePluginLoader.h>
28 #include <C2PlatformSupport.h>
29 #include <util/C2InterfaceHelper.h>
30
31 #include <dlfcn.h>
32 #include <unistd.h> // getpagesize
33
34 #include <map>
35 #include <memory>
36 #include <mutex>
37
38 #ifdef __ANDROID_APEX__
39 #include <android-base/properties.h>
40 #endif
41
42 namespace android {
43
44 /**
45 * Returns the preferred component store in this process to access its interface.
46 */
47 std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore();
48
49 /**
50 * The platform allocator store provides basic allocator-types for the framework based on ion and
51 * gralloc. Allocators are not meant to be updatable.
52 *
53 * \todo Provide allocator based on ashmem
54 * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
55 * \todo Make this allocator store extendable
56 */
57 class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
58 public:
59 C2PlatformAllocatorStoreImpl();
60
61 virtual c2_status_t fetchAllocator(
62 id_t id, std::shared_ptr<C2Allocator> *const allocator) override;
63
listAllocators_nb() const64 virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb()
65 const override {
66 return std::vector<std::shared_ptr<const C2Allocator::Traits>>(); /// \todo
67 }
68
getName() const69 virtual C2String getName() const override {
70 return "android.allocator-store";
71 }
72
73 void setComponentStore(std::shared_ptr<C2ComponentStore> store);
74
75 ~C2PlatformAllocatorStoreImpl() override = default;
76
77 private:
78 /// returns a shared-singleton ion allocator
79 std::shared_ptr<C2Allocator> fetchIonAllocator();
80
81 /// returns a shared-singleton gralloc allocator
82 std::shared_ptr<C2Allocator> fetchGrallocAllocator();
83
84 /// returns a shared-singleton bufferqueue supporting gralloc allocator
85 std::shared_ptr<C2Allocator> fetchBufferQueueAllocator();
86
87 /// component store to use
88 std::mutex _mComponentStoreSetLock; // protects the entire updating _mComponentStore and its
89 // dependencies
90 std::mutex _mComponentStoreReadLock; // must protect only read/write of _mComponentStore
91 std::shared_ptr<C2ComponentStore> _mComponentStore;
92 };
93
C2PlatformAllocatorStoreImpl()94 C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
95 }
96
fetchAllocator(id_t id,std::shared_ptr<C2Allocator> * const allocator)97 c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
98 id_t id, std::shared_ptr<C2Allocator> *const allocator) {
99 allocator->reset();
100 switch (id) {
101 // TODO: should we implement a generic registry for all, and use that?
102 case C2PlatformAllocatorStore::ION:
103 case C2AllocatorStore::DEFAULT_LINEAR:
104 *allocator = fetchIonAllocator();
105 break;
106
107 case C2PlatformAllocatorStore::GRALLOC:
108 case C2AllocatorStore::DEFAULT_GRAPHIC:
109 *allocator = fetchGrallocAllocator();
110 break;
111
112 case C2PlatformAllocatorStore::BUFFERQUEUE:
113 *allocator = fetchBufferQueueAllocator();
114 break;
115
116 default:
117 // Try to create allocator from platform store plugins.
118 c2_status_t res =
119 C2PlatformStorePluginLoader::GetInstance()->createAllocator(id, allocator);
120 if (res != C2_OK) {
121 return res;
122 }
123 break;
124 }
125 if (*allocator == nullptr) {
126 return C2_NO_MEMORY;
127 }
128 return C2_OK;
129 }
130
131 namespace {
132
133 std::mutex gIonAllocatorMutex;
134 std::weak_ptr<C2AllocatorIon> gIonAllocator;
135
UseComponentStoreForIonAllocator(const std::shared_ptr<C2AllocatorIon> allocator,std::shared_ptr<C2ComponentStore> store)136 void UseComponentStoreForIonAllocator(
137 const std::shared_ptr<C2AllocatorIon> allocator,
138 std::shared_ptr<C2ComponentStore> store) {
139 C2AllocatorIon::UsageMapperFn mapper;
140 uint64_t minUsage = 0;
141 uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected;
142 size_t blockSize = getpagesize();
143
144 // query min and max usage as well as block size via supported values
145 C2StoreIonUsageInfo usageInfo;
146 std::vector<C2FieldSupportedValuesQuery> query = {
147 C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.usage)),
148 C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.capacity)),
149 };
150 c2_status_t res = store->querySupportedValues_sm(query);
151 if (res == C2_OK) {
152 if (query[0].status == C2_OK) {
153 const C2FieldSupportedValues &fsv = query[0].values;
154 if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) {
155 minUsage = fsv.values[0].u64;
156 maxUsage = 0;
157 for (C2Value::Primitive v : fsv.values) {
158 maxUsage |= v.u64;
159 }
160 }
161 }
162 if (query[1].status == C2_OK) {
163 const C2FieldSupportedValues &fsv = query[1].values;
164 if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) {
165 blockSize = fsv.range.step.u32;
166 }
167 }
168
169 mapper = [store](C2MemoryUsage usage, size_t capacity,
170 size_t *align, unsigned *heapMask, unsigned *flags) -> c2_status_t {
171 if (capacity > UINT32_MAX) {
172 return C2_BAD_VALUE;
173 }
174 C2StoreIonUsageInfo usageInfo = { usage.expected, capacity };
175 std::vector<std::unique_ptr<C2SettingResult>> failures; // TODO: remove
176 c2_status_t res = store->config_sm({&usageInfo}, &failures);
177 if (res == C2_OK) {
178 *align = usageInfo.minAlignment;
179 *heapMask = usageInfo.heapMask;
180 *flags = usageInfo.allocFlags;
181 }
182 return res;
183 };
184 }
185
186 allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize);
187 }
188
189 }
190
setComponentStore(std::shared_ptr<C2ComponentStore> store)191 void C2PlatformAllocatorStoreImpl::setComponentStore(std::shared_ptr<C2ComponentStore> store) {
192 // technically this set lock is not needed, but is here for safety in case we add more
193 // getter orders
194 std::lock_guard<std::mutex> lock(_mComponentStoreSetLock);
195 {
196 std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
197 _mComponentStore = store;
198 }
199 std::shared_ptr<C2AllocatorIon> allocator;
200 {
201 std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
202 allocator = gIonAllocator.lock();
203 }
204 if (allocator) {
205 UseComponentStoreForIonAllocator(allocator, store);
206 }
207 }
208
fetchIonAllocator()209 std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
210 std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
211 std::shared_ptr<C2AllocatorIon> allocator = gIonAllocator.lock();
212 if (allocator == nullptr) {
213 std::shared_ptr<C2ComponentStore> componentStore;
214 {
215 std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
216 componentStore = _mComponentStore;
217 }
218 allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
219 UseComponentStoreForIonAllocator(allocator, componentStore);
220 gIonAllocator = allocator;
221 }
222 return allocator;
223 }
224
fetchGrallocAllocator()225 std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
226 static std::mutex mutex;
227 static std::weak_ptr<C2Allocator> grallocAllocator;
228 std::lock_guard<std::mutex> lock(mutex);
229 std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
230 if (allocator == nullptr) {
231 allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
232 grallocAllocator = allocator;
233 }
234 return allocator;
235 }
236
fetchBufferQueueAllocator()237 std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBufferQueueAllocator() {
238 static std::mutex mutex;
239 static std::weak_ptr<C2Allocator> grallocAllocator;
240 std::lock_guard<std::mutex> lock(mutex);
241 std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
242 if (allocator == nullptr) {
243 allocator = std::make_shared<C2AllocatorGralloc>(
244 C2PlatformAllocatorStore::BUFFERQUEUE, true);
245 grallocAllocator = allocator;
246 }
247 return allocator;
248 }
249
250 namespace {
251 std::mutex gPreferredComponentStoreMutex;
252 std::shared_ptr<C2ComponentStore> gPreferredComponentStore;
253
254 std::mutex gPlatformAllocatorStoreMutex;
255 std::weak_ptr<C2PlatformAllocatorStoreImpl> gPlatformAllocatorStore;
256 }
257
GetCodec2PlatformAllocatorStore()258 std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
259 std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
260 std::shared_ptr<C2PlatformAllocatorStoreImpl> store = gPlatformAllocatorStore.lock();
261 if (store == nullptr) {
262 store = std::make_shared<C2PlatformAllocatorStoreImpl>();
263 store->setComponentStore(GetPreferredCodec2ComponentStore());
264 gPlatformAllocatorStore = store;
265 }
266 return store;
267 }
268
SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore)269 void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore) {
270 static std::mutex mutex;
271 std::lock_guard<std::mutex> lock(mutex); // don't interleve set-s
272
273 // update preferred store
274 {
275 std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
276 gPreferredComponentStore = componentStore;
277 }
278
279 // update platform allocator's store as well if it is alive
280 std::shared_ptr<C2PlatformAllocatorStoreImpl> allocatorStore;
281 {
282 std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
283 allocatorStore = gPlatformAllocatorStore.lock();
284 }
285 if (allocatorStore) {
286 allocatorStore->setComponentStore(componentStore);
287 }
288 }
289
GetPreferredCodec2ComponentStore()290 std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore() {
291 std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
292 return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore();
293 }
294
295 namespace {
296
297 class _C2BlockPoolCache {
298 public:
_C2BlockPoolCache()299 _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
300
_createBlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,C2BlockPool::local_id_t poolId,std::shared_ptr<C2BlockPool> * pool)301 c2_status_t _createBlockPool(
302 C2PlatformAllocatorStore::id_t allocatorId,
303 std::shared_ptr<const C2Component> component,
304 C2BlockPool::local_id_t poolId,
305 std::shared_ptr<C2BlockPool> *pool) {
306 std::shared_ptr<C2AllocatorStore> allocatorStore =
307 GetCodec2PlatformAllocatorStore();
308 std::shared_ptr<C2Allocator> allocator;
309 c2_status_t res = C2_NOT_FOUND;
310
311 switch(allocatorId) {
312 case C2PlatformAllocatorStore::ION:
313 case C2AllocatorStore::DEFAULT_LINEAR:
314 res = allocatorStore->fetchAllocator(
315 C2AllocatorStore::DEFAULT_LINEAR, &allocator);
316 if (res == C2_OK) {
317 std::shared_ptr<C2BlockPool> ptr =
318 std::make_shared<C2PooledBlockPool>(
319 allocator, poolId);
320 *pool = ptr;
321 mBlockPools[poolId] = ptr;
322 mComponents[poolId] = component;
323 }
324 break;
325 case C2PlatformAllocatorStore::GRALLOC:
326 case C2AllocatorStore::DEFAULT_GRAPHIC:
327 res = allocatorStore->fetchAllocator(
328 C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
329 if (res == C2_OK) {
330 std::shared_ptr<C2BlockPool> ptr =
331 std::make_shared<C2PooledBlockPool>(allocator, poolId);
332 *pool = ptr;
333 mBlockPools[poolId] = ptr;
334 mComponents[poolId] = component;
335 }
336 break;
337 case C2PlatformAllocatorStore::BUFFERQUEUE:
338 res = allocatorStore->fetchAllocator(
339 C2PlatformAllocatorStore::BUFFERQUEUE, &allocator);
340 if (res == C2_OK) {
341 std::shared_ptr<C2BlockPool> ptr =
342 std::make_shared<C2BufferQueueBlockPool>(
343 allocator, poolId);
344 *pool = ptr;
345 mBlockPools[poolId] = ptr;
346 mComponents[poolId] = component;
347 }
348 break;
349 default:
350 // Try to create block pool from platform store plugins.
351 std::shared_ptr<C2BlockPool> ptr;
352 res = C2PlatformStorePluginLoader::GetInstance()->createBlockPool(
353 allocatorId, poolId, &ptr);
354 if (res == C2_OK) {
355 *pool = ptr;
356 mBlockPools[poolId] = ptr;
357 mComponents[poolId] = component;
358 }
359 break;
360 }
361 return res;
362 }
363
createBlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)364 c2_status_t createBlockPool(
365 C2PlatformAllocatorStore::id_t allocatorId,
366 std::shared_ptr<const C2Component> component,
367 std::shared_ptr<C2BlockPool> *pool) {
368 return _createBlockPool(allocatorId, component, mBlockPoolSeqId++, pool);
369 }
370
getBlockPool(C2BlockPool::local_id_t blockPoolId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)371 bool getBlockPool(
372 C2BlockPool::local_id_t blockPoolId,
373 std::shared_ptr<const C2Component> component,
374 std::shared_ptr<C2BlockPool> *pool) {
375 // TODO: use one iterator for multiple blockpool type scalability.
376 std::shared_ptr<C2BlockPool> ptr;
377 auto it = mBlockPools.find(blockPoolId);
378 if (it != mBlockPools.end()) {
379 ptr = it->second.lock();
380 if (!ptr) {
381 mBlockPools.erase(it);
382 mComponents.erase(blockPoolId);
383 } else {
384 auto found = mComponents.find(blockPoolId);
385 if (component == found->second.lock()) {
386 *pool = ptr;
387 return true;
388 }
389 }
390 }
391 return false;
392 }
393
394 private:
395 C2BlockPool::local_id_t mBlockPoolSeqId;
396
397 std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
398 std::map<C2BlockPool::local_id_t, std::weak_ptr<const C2Component>> mComponents;
399 };
400
401 static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
402 std::make_unique<_C2BlockPoolCache>();
403 static std::mutex sBlockPoolCacheMutex;
404
405 } // anynymous namespace
406
GetCodec2BlockPool(C2BlockPool::local_id_t id,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)407 c2_status_t GetCodec2BlockPool(
408 C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
409 std::shared_ptr<C2BlockPool> *pool) {
410 pool->reset();
411 std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
412 std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
413 std::shared_ptr<C2Allocator> allocator;
414 c2_status_t res = C2_NOT_FOUND;
415
416 if (id >= C2BlockPool::PLATFORM_START) {
417 if (sBlockPoolCache->getBlockPool(id, component, pool)) {
418 return C2_OK;
419 }
420 }
421
422 switch (id) {
423 case C2BlockPool::BASIC_LINEAR:
424 res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
425 if (res == C2_OK) {
426 *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
427 }
428 break;
429 case C2BlockPool::BASIC_GRAPHIC:
430 res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
431 if (res == C2_OK) {
432 *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
433 }
434 break;
435 // TODO: remove this. this is temporary
436 case C2BlockPool::PLATFORM_START:
437 res = sBlockPoolCache->_createBlockPool(
438 C2PlatformAllocatorStore::BUFFERQUEUE, component, id, pool);
439 break;
440 default:
441 break;
442 }
443 return res;
444 }
445
CreateCodec2BlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)446 c2_status_t CreateCodec2BlockPool(
447 C2PlatformAllocatorStore::id_t allocatorId,
448 std::shared_ptr<const C2Component> component,
449 std::shared_ptr<C2BlockPool> *pool) {
450 pool->reset();
451
452 std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
453 return sBlockPoolCache->createBlockPool(allocatorId, component, pool);
454 }
455
456 class C2PlatformComponentStore : public C2ComponentStore {
457 public:
458 virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
459 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
460 virtual C2String getName() const override;
461 virtual c2_status_t querySupportedValues_sm(
462 std::vector<C2FieldSupportedValuesQuery> &fields) const override;
463 virtual c2_status_t querySupportedParams_nb(
464 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override;
465 virtual c2_status_t query_sm(
466 const std::vector<C2Param*> &stackParams,
467 const std::vector<C2Param::Index> &heapParamIndices,
468 std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
469 virtual c2_status_t createInterface(
470 C2String name, std::shared_ptr<C2ComponentInterface> *const interface) override;
471 virtual c2_status_t createComponent(
472 C2String name, std::shared_ptr<C2Component> *const component) override;
473 virtual c2_status_t copyBuffer(
474 std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) override;
475 virtual c2_status_t config_sm(
476 const std::vector<C2Param*> ¶ms,
477 std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
478 C2PlatformComponentStore();
479
480 virtual ~C2PlatformComponentStore() override = default;
481
482 private:
483
484 /**
485 * An object encapsulating a loaded component module.
486 *
487 * \todo provide a way to add traits to known components here to avoid loading the .so-s
488 * for listComponents
489 */
490 struct ComponentModule : public C2ComponentFactory,
491 public std::enable_shared_from_this<ComponentModule> {
492 virtual c2_status_t createComponent(
493 c2_node_id_t id, std::shared_ptr<C2Component> *component,
494 ComponentDeleter deleter = std::default_delete<C2Component>()) override;
495 virtual c2_status_t createInterface(
496 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
497 InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;
498
499 /**
500 * \returns the traits of the component in this module.
501 */
502 std::shared_ptr<const C2Component::Traits> getTraits();
503
504 /**
505 * Creates an uninitialized component module.
506 *
507 * \param name[in] component name.
508 *
509 * \note Only used by ComponentLoader.
510 */
ComponentModuleandroid::C2PlatformComponentStore::ComponentModule511 ComponentModule()
512 : mInit(C2_NO_INIT),
513 mLibHandle(nullptr),
514 createFactory(nullptr),
515 destroyFactory(nullptr),
516 mComponentFactory(nullptr) {
517 }
518
519 /**
520 * Initializes a component module with a given library path. Must be called exactly once.
521 *
522 * \note Only used by ComponentLoader.
523 *
524 * \param libPath[in] library path
525 *
526 * \retval C2_OK the component module has been successfully loaded
527 * \retval C2_NO_MEMORY not enough memory to loading the component module
528 * \retval C2_NOT_FOUND could not locate the component module
529 * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
530 * \retval C2_REFUSED permission denied to load the component module (unexpected)
531 * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
532 */
533 c2_status_t init(std::string libPath);
534
535 virtual ~ComponentModule() override;
536
537 protected:
538 std::recursive_mutex mLock; ///< lock protecting mTraits
539 std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
540
541 c2_status_t mInit; ///< initialization result
542
543 void *mLibHandle; ///< loaded library handle
544 C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
545 C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
546 C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
547 };
548
549 /**
550 * An object encapsulating a loadable component module.
551 *
552 * \todo make this also work for enumerations
553 */
554 struct ComponentLoader {
555 /**
556 * Load the component module.
557 *
558 * This method simply returns the component module if it is already currently loaded, or
559 * attempts to load it if it is not.
560 *
561 * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
562 * This will be nullptr on error.
563 *
564 * \retval C2_OK the component module has been successfully loaded
565 * \retval C2_NO_MEMORY not enough memory to loading the component module
566 * \retval C2_NOT_FOUND could not locate the component module
567 * \retval C2_CORRUPTED the component module could not be loaded
568 * \retval C2_REFUSED permission denied to load the component module
569 */
fetchModuleandroid::C2PlatformComponentStore::ComponentLoader570 c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
571 c2_status_t res = C2_OK;
572 std::lock_guard<std::mutex> lock(mMutex);
573 std::shared_ptr<ComponentModule> localModule = mModule.lock();
574 if (localModule == nullptr) {
575 localModule = std::make_shared<ComponentModule>();
576 res = localModule->init(mLibPath);
577 if (res == C2_OK) {
578 mModule = localModule;
579 }
580 }
581 *module = localModule;
582 return res;
583 }
584
585 /**
586 * Creates a component loader for a specific library path (or name).
587 */
ComponentLoaderandroid::C2PlatformComponentStore::ComponentLoader588 ComponentLoader(std::string libPath)
589 : mLibPath(libPath) {}
590
591 private:
592 std::mutex mMutex; ///< mutex guarding the module
593 std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
594 std::string mLibPath; ///< library path
595 };
596
597 struct Interface : public C2InterfaceHelper {
598 std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
599
Interfaceandroid::C2PlatformComponentStore::Interface600 Interface(std::shared_ptr<C2ReflectorHelper> reflector)
601 : C2InterfaceHelper(reflector) {
602 setDerivedInstance(this);
603
604 struct Setter {
605 static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
606 #ifdef __ANDROID_APEX__
607 static int32_t defaultHeapMask = [] {
608 int32_t heapmask = base::GetIntProperty(
609 "ro.com.android.media.swcodec.ion.heapmask", int32_t(0xFFFFFFFF));
610 ALOGD("Default ION heapmask = %d", heapmask);
611 return heapmask;
612 }();
613 static int32_t defaultFlags = [] {
614 int32_t flags = base::GetIntProperty(
615 "ro.com.android.media.swcodec.ion.flags", 0);
616 ALOGD("Default ION flags = %d", flags);
617 return flags;
618 }();
619 static uint32_t defaultAlign = [] {
620 uint32_t align = base::GetUintProperty(
621 "ro.com.android.media.swcodec.ion.align", 0u);
622 ALOGD("Default ION align = %d", align);
623 return align;
624 }();
625 me.set().heapMask = defaultHeapMask;
626 me.set().allocFlags = defaultFlags;
627 me.set().minAlignment = defaultAlign;
628 #else
629 me.set().heapMask = ~0;
630 me.set().allocFlags = 0;
631 me.set().minAlignment = 0;
632 #endif
633 return C2R::Ok();
634 }
635 };
636
637 addParameter(
638 DefineParam(mIonUsageInfo, "ion-usage")
639 .withDefault(new C2StoreIonUsageInfo())
640 .withFields({
641 C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
642 C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
643 C2F(mIonUsageInfo, heapMask).any(),
644 C2F(mIonUsageInfo, allocFlags).flags({}),
645 C2F(mIonUsageInfo, minAlignment).equalTo(0)
646 })
647 .withSetter(Setter::setIonUsage)
648 .build());
649 }
650 };
651
652 /**
653 * Retrieves the component module for a component.
654 *
655 * \param module pointer to a shared_pointer where the component module will be stored on
656 * success.
657 *
658 * \retval C2_OK the component loader has been successfully retrieved
659 * \retval C2_NO_MEMORY not enough memory to locate the component loader
660 * \retval C2_NOT_FOUND could not locate the component to be loaded
661 * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
662 * corrupted (this can happen if the name does not refer to an already
663 * identified component but some components could not be loaded due to
664 * bad library)
665 * \retval C2_REFUSED permission denied to find the component loader for the named component
666 * (this can happen if the name does not refer to an already identified
667 * component but some components could not be loaded due to lack of
668 * permissions)
669 */
670 c2_status_t findComponent(C2String name, std::shared_ptr<ComponentModule> *module);
671
672 /**
673 * Loads each component module and discover its contents.
674 */
675 void visitComponents();
676
677 std::mutex mMutex; ///< mutex guarding the component lists during construction
678 bool mVisited; ///< component modules visited
679 std::map<C2String, ComponentLoader> mComponents; ///< path -> component module
680 std::map<C2String, C2String> mComponentNameToPath; ///< name -> path
681 std::vector<std::shared_ptr<const C2Component::Traits>> mComponentList;
682
683 std::shared_ptr<C2ReflectorHelper> mReflector;
684 Interface mInterface;
685 };
686
init(std::string libPath)687 c2_status_t C2PlatformComponentStore::ComponentModule::init(
688 std::string libPath) {
689 ALOGV("in %s", __func__);
690 ALOGV("loading dll");
691 mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
692 LOG_ALWAYS_FATAL_IF(mLibHandle == nullptr,
693 "could not dlopen %s: %s", libPath.c_str(), dlerror());
694
695 createFactory =
696 (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
697 LOG_ALWAYS_FATAL_IF(createFactory == nullptr,
698 "createFactory is null in %s", libPath.c_str());
699
700 destroyFactory =
701 (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
702 LOG_ALWAYS_FATAL_IF(destroyFactory == nullptr,
703 "destroyFactory is null in %s", libPath.c_str());
704
705 mComponentFactory = createFactory();
706 if (mComponentFactory == nullptr) {
707 ALOGD("could not create factory in %s", libPath.c_str());
708 mInit = C2_NO_MEMORY;
709 } else {
710 mInit = C2_OK;
711 }
712
713 if (mInit != C2_OK) {
714 return mInit;
715 }
716
717 std::shared_ptr<C2ComponentInterface> intf;
718 c2_status_t res = createInterface(0, &intf);
719 if (res != C2_OK) {
720 ALOGD("failed to create interface: %d", res);
721 return mInit;
722 }
723
724 std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
725 if (traits) {
726 traits->name = intf->getName();
727
728 C2ComponentKindSetting kind;
729 C2ComponentDomainSetting domain;
730 res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
731 bool fixDomain = res != C2_OK;
732 if (res == C2_OK) {
733 traits->kind = kind.value;
734 traits->domain = domain.value;
735 } else {
736 // TODO: remove this fall-back
737 ALOGD("failed to query interface for kind and domain: %d", res);
738
739 traits->kind =
740 (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
741 (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
742 C2Component::KIND_OTHER;
743 }
744
745 uint32_t mediaTypeIndex =
746 traits->kind == C2Component::KIND_ENCODER ? C2PortMediaTypeSetting::output::PARAM_TYPE
747 : C2PortMediaTypeSetting::input::PARAM_TYPE;
748 std::vector<std::unique_ptr<C2Param>> params;
749 res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, ¶ms);
750 if (res != C2_OK) {
751 ALOGD("failed to query interface: %d", res);
752 return mInit;
753 }
754 if (params.size() != 1u) {
755 ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
756 return mInit;
757 }
758 C2PortMediaTypeSetting *mediaTypeConfig = C2PortMediaTypeSetting::From(params[0].get());
759 if (mediaTypeConfig == nullptr) {
760 ALOGD("failed to query media type");
761 return mInit;
762 }
763 traits->mediaType =
764 std::string(mediaTypeConfig->m.value,
765 strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
766
767 if (fixDomain) {
768 if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
769 traits->domain = C2Component::DOMAIN_AUDIO;
770 } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
771 traits->domain = C2Component::DOMAIN_VIDEO;
772 } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
773 traits->domain = C2Component::DOMAIN_IMAGE;
774 } else {
775 traits->domain = C2Component::DOMAIN_OTHER;
776 }
777 }
778
779 // TODO: get this properly from the store during emplace
780 switch (traits->domain) {
781 case C2Component::DOMAIN_AUDIO:
782 traits->rank = 8;
783 break;
784 default:
785 traits->rank = 512;
786 }
787
788 params.clear();
789 res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, ¶ms);
790 if (res == C2_OK && params.size() == 1u) {
791 C2ComponentAliasesSetting *aliasesSetting =
792 C2ComponentAliasesSetting::From(params[0].get());
793 if (aliasesSetting) {
794 // Split aliases on ','
795 // This looks simpler in plain C and even std::string would still make a copy.
796 char *aliases = ::strndup(aliasesSetting->m.value, aliasesSetting->flexCount());
797 ALOGD("'%s' has aliases: '%s'", intf->getName().c_str(), aliases);
798
799 for (char *tok, *ptr, *str = aliases; (tok = ::strtok_r(str, ",", &ptr));
800 str = nullptr) {
801 traits->aliases.push_back(tok);
802 ALOGD("adding alias: '%s'", tok);
803 }
804 free(aliases);
805 }
806 }
807 }
808 mTraits = traits;
809
810 return mInit;
811 }
812
~ComponentModule()813 C2PlatformComponentStore::ComponentModule::~ComponentModule() {
814 ALOGV("in %s", __func__);
815 if (destroyFactory && mComponentFactory) {
816 destroyFactory(mComponentFactory);
817 }
818 if (mLibHandle) {
819 ALOGV("unloading dll");
820 dlclose(mLibHandle);
821 }
822 }
823
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * interface,std::function<void (::C2ComponentInterface *)> deleter)824 c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
825 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
826 std::function<void(::C2ComponentInterface*)> deleter) {
827 interface->reset();
828 if (mInit != C2_OK) {
829 return mInit;
830 }
831 std::shared_ptr<ComponentModule> module = shared_from_this();
832 c2_status_t res = mComponentFactory->createInterface(
833 id, interface, [module, deleter](C2ComponentInterface *p) mutable {
834 // capture module so that we ensure we still have it while deleting interface
835 deleter(p); // delete interface first
836 module.reset(); // remove module ref (not technically needed)
837 });
838 return res;
839 }
840
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * component,std::function<void (::C2Component *)> deleter)841 c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
842 c2_node_id_t id, std::shared_ptr<C2Component> *component,
843 std::function<void(::C2Component*)> deleter) {
844 component->reset();
845 if (mInit != C2_OK) {
846 return mInit;
847 }
848 std::shared_ptr<ComponentModule> module = shared_from_this();
849 c2_status_t res = mComponentFactory->createComponent(
850 id, component, [module, deleter](C2Component *p) mutable {
851 // capture module so that we ensure we still have it while deleting component
852 deleter(p); // delete component first
853 module.reset(); // remove module ref (not technically needed)
854 });
855 return res;
856 }
857
getTraits()858 std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
859 std::unique_lock<std::recursive_mutex> lock(mLock);
860 return mTraits;
861 }
862
C2PlatformComponentStore()863 C2PlatformComponentStore::C2PlatformComponentStore()
864 : mVisited(false),
865 mReflector(std::make_shared<C2ReflectorHelper>()),
866 mInterface(mReflector) {
867
868 auto emplace = [this](const char *libPath) {
869 mComponents.emplace(libPath, libPath);
870 };
871
872 // TODO: move this also into a .so so it can be updated
873 emplace("libcodec2_soft_aacdec.so");
874 emplace("libcodec2_soft_aacenc.so");
875 emplace("libcodec2_soft_amrnbdec.so");
876 emplace("libcodec2_soft_amrnbenc.so");
877 emplace("libcodec2_soft_amrwbdec.so");
878 emplace("libcodec2_soft_amrwbenc.so");
879 //emplace("libcodec2_soft_av1dec_aom.so"); // deprecated for the gav1 implementation
880 emplace("libcodec2_soft_av1dec_gav1.so");
881 emplace("libcodec2_soft_avcdec.so");
882 emplace("libcodec2_soft_avcenc.so");
883 emplace("libcodec2_soft_flacdec.so");
884 emplace("libcodec2_soft_flacenc.so");
885 emplace("libcodec2_soft_g711alawdec.so");
886 emplace("libcodec2_soft_g711mlawdec.so");
887 emplace("libcodec2_soft_gsmdec.so");
888 emplace("libcodec2_soft_h263dec.so");
889 emplace("libcodec2_soft_h263enc.so");
890 emplace("libcodec2_soft_hevcdec.so");
891 emplace("libcodec2_soft_hevcenc.so");
892 emplace("libcodec2_soft_mp3dec.so");
893 emplace("libcodec2_soft_mpeg2dec.so");
894 emplace("libcodec2_soft_mpeg4dec.so");
895 emplace("libcodec2_soft_mpeg4enc.so");
896 emplace("libcodec2_soft_opusdec.so");
897 emplace("libcodec2_soft_opusenc.so");
898 emplace("libcodec2_soft_rawdec.so");
899 emplace("libcodec2_soft_vorbisdec.so");
900 emplace("libcodec2_soft_vp8dec.so");
901 emplace("libcodec2_soft_vp8enc.so");
902 emplace("libcodec2_soft_vp9dec.so");
903 emplace("libcodec2_soft_vp9enc.so");
904 }
905
copyBuffer(std::shared_ptr<C2GraphicBuffer> src,std::shared_ptr<C2GraphicBuffer> dst)906 c2_status_t C2PlatformComponentStore::copyBuffer(
907 std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
908 (void)src;
909 (void)dst;
910 return C2_OMITTED;
911 }
912
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const913 c2_status_t C2PlatformComponentStore::query_sm(
914 const std::vector<C2Param*> &stackParams,
915 const std::vector<C2Param::Index> &heapParamIndices,
916 std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
917 return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
918 }
919
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)920 c2_status_t C2PlatformComponentStore::config_sm(
921 const std::vector<C2Param*> ¶ms,
922 std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
923 return mInterface.config(params, C2_MAY_BLOCK, failures);
924 }
925
visitComponents()926 void C2PlatformComponentStore::visitComponents() {
927 std::lock_guard<std::mutex> lock(mMutex);
928 if (mVisited) {
929 return;
930 }
931 for (auto &pathAndLoader : mComponents) {
932 const C2String &path = pathAndLoader.first;
933 ComponentLoader &loader = pathAndLoader.second;
934 std::shared_ptr<ComponentModule> module;
935 if (loader.fetchModule(&module) == C2_OK) {
936 std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
937 if (traits) {
938 mComponentList.push_back(traits);
939 mComponentNameToPath.emplace(traits->name, path);
940 for (const C2String &alias : traits->aliases) {
941 mComponentNameToPath.emplace(alias, path);
942 }
943 }
944 }
945 }
946 mVisited = true;
947 }
948
listComponents()949 std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
950 // This method SHALL return within 500ms.
951 visitComponents();
952 return mComponentList;
953 }
954
findComponent(C2String name,std::shared_ptr<ComponentModule> * module)955 c2_status_t C2PlatformComponentStore::findComponent(
956 C2String name, std::shared_ptr<ComponentModule> *module) {
957 (*module).reset();
958 visitComponents();
959
960 auto pos = mComponentNameToPath.find(name);
961 if (pos != mComponentNameToPath.end()) {
962 return mComponents.at(pos->second).fetchModule(module);
963 }
964 return C2_NOT_FOUND;
965 }
966
createComponent(C2String name,std::shared_ptr<C2Component> * const component)967 c2_status_t C2PlatformComponentStore::createComponent(
968 C2String name, std::shared_ptr<C2Component> *const component) {
969 // This method SHALL return within 100ms.
970 component->reset();
971 std::shared_ptr<ComponentModule> module;
972 c2_status_t res = findComponent(name, &module);
973 if (res == C2_OK) {
974 // TODO: get a unique node ID
975 res = module->createComponent(0, component);
976 }
977 return res;
978 }
979
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)980 c2_status_t C2PlatformComponentStore::createInterface(
981 C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
982 // This method SHALL return within 100ms.
983 interface->reset();
984 std::shared_ptr<ComponentModule> module;
985 c2_status_t res = findComponent(name, &module);
986 if (res == C2_OK) {
987 // TODO: get a unique node ID
988 res = module->createInterface(0, interface);
989 }
990 return res;
991 }
992
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const993 c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
994 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
995 return mInterface.querySupportedParams(params);
996 }
997
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const998 c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
999 std::vector<C2FieldSupportedValuesQuery> &fields) const {
1000 return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
1001 }
1002
getName() const1003 C2String C2PlatformComponentStore::getName() const {
1004 return "android.componentStore.platform";
1005 }
1006
getParamReflector() const1007 std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
1008 return mReflector;
1009 }
1010
GetCodec2PlatformComponentStore()1011 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
1012 static std::mutex mutex;
1013 static std::weak_ptr<C2ComponentStore> platformStore;
1014 std::lock_guard<std::mutex> lock(mutex);
1015 std::shared_ptr<C2ComponentStore> store = platformStore.lock();
1016 if (store == nullptr) {
1017 store = std::make_shared<C2PlatformComponentStore>();
1018 platformStore = store;
1019 }
1020 return store;
1021 }
1022
1023 } // namespace android
1024