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*> &params,
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, &params);
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, &params);
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*> &params,
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