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