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 alias[in]   module alias
521          * \param libPath[in] library path
522          *
523          * \retval C2_OK        the component module has been successfully loaded
524          * \retval C2_NO_MEMORY not enough memory to loading the component module
525          * \retval C2_NOT_FOUND could not locate the component module
526          * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
527          * \retval C2_REFUSED   permission denied to load the component module (unexpected)
528          * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
529          */
530         c2_status_t init(std::string alias, std::string libPath);
531 
532         virtual ~ComponentModule() override;
533 
534     protected:
535         std::recursive_mutex mLock; ///< lock protecting mTraits
536         std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
537 
538         c2_status_t mInit; ///< initialization result
539 
540         void *mLibHandle; ///< loaded library handle
541         C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
542         C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
543         C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
544     };
545 
546     /**
547      * An object encapsulating a loadable component module.
548      *
549      * \todo make this also work for enumerations
550      */
551     struct ComponentLoader {
552         /**
553          * Load the component module.
554          *
555          * This method simply returns the component module if it is already currently loaded, or
556          * attempts to load it if it is not.
557          *
558          * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
559          *                    This will be nullptr on error.
560          *
561          * \retval C2_OK        the component module has been successfully loaded
562          * \retval C2_NO_MEMORY not enough memory to loading the component module
563          * \retval C2_NOT_FOUND could not locate the component module
564          * \retval C2_CORRUPTED the component module could not be loaded
565          * \retval C2_REFUSED   permission denied to load the component module
566          */
fetchModuleandroid::C2PlatformComponentStore::ComponentLoader567         c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
568             c2_status_t res = C2_OK;
569             std::lock_guard<std::mutex> lock(mMutex);
570             std::shared_ptr<ComponentModule> localModule = mModule.lock();
571             if (localModule == nullptr) {
572                 localModule = std::make_shared<ComponentModule>();
573                 res = localModule->init(mAlias, mLibPath);
574                 if (res == C2_OK) {
575                     mModule = localModule;
576                 }
577             }
578             *module = localModule;
579             return res;
580         }
581 
582         /**
583          * Creates a component loader for a specific library path (or name).
584          */
ComponentLoaderandroid::C2PlatformComponentStore::ComponentLoader585         ComponentLoader(std::string alias, std::string libPath)
586             : mAlias(alias), mLibPath(libPath) {}
587 
588     private:
589         std::mutex mMutex; ///< mutex guarding the module
590         std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
591         std::string mAlias; ///< component alias
592         std::string mLibPath; ///< library path
593     };
594 
595     struct Interface : public C2InterfaceHelper {
596         std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
597 
Interfaceandroid::C2PlatformComponentStore::Interface598         Interface(std::shared_ptr<C2ReflectorHelper> reflector)
599             : C2InterfaceHelper(reflector) {
600             setDerivedInstance(this);
601 
602             struct Setter {
603                 static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
604                     me.set().heapMask = ~0;
605                     me.set().allocFlags = 0;
606                     me.set().minAlignment = 0;
607                     return C2R::Ok();
608                 }
609             };
610 
611             addParameter(
612                 DefineParam(mIonUsageInfo, "ion-usage")
613                 .withDefault(new C2StoreIonUsageInfo())
614                 .withFields({
615                     C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
616                     C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
617                     C2F(mIonUsageInfo, heapMask).any(),
618                     C2F(mIonUsageInfo, allocFlags).flags({}),
619                     C2F(mIonUsageInfo, minAlignment).equalTo(0)
620                 })
621                 .withSetter(Setter::setIonUsage)
622                 .build());
623         }
624     };
625 
626     /**
627      * Retrieves the component loader for a component.
628      *
629      * \return a non-ref-holding pointer to the component loader.
630      *
631      * \retval C2_OK        the component loader has been successfully retrieved
632      * \retval C2_NO_MEMORY not enough memory to locate the component loader
633      * \retval C2_NOT_FOUND could not locate the component to be loaded
634      * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
635      *                      corrupted (this can happen if the name does not refer to an already
636      *                      identified component but some components could not be loaded due to
637      *                      bad library)
638      * \retval C2_REFUSED   permission denied to find the component loader for the named component
639      *                      (this can happen if the name does not refer to an already identified
640      *                      component but some components could not be loaded due to lack of
641      *                      permissions)
642      */
643     c2_status_t findComponent(C2String name, ComponentLoader **loader);
644 
645     std::map<C2String, ComponentLoader> mComponents; ///< map of name -> components
646     std::vector<C2String> mComponentsList; ///< list of components
647     std::shared_ptr<C2ReflectorHelper> mReflector;
648     Interface mInterface;
649 };
650 
init(std::string alias,std::string libPath)651 c2_status_t C2PlatformComponentStore::ComponentModule::init(
652         std::string alias, std::string libPath) {
653     ALOGV("in %s", __func__);
654     ALOGV("loading dll");
655     mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
656     if (mLibHandle == nullptr) {
657         // could be access/symbol or simply not being there
658         ALOGD("could not dlopen %s: %s", libPath.c_str(), dlerror());
659         mInit = C2_CORRUPTED;
660     } else {
661         createFactory =
662             (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
663         destroyFactory =
664             (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
665 
666         mComponentFactory = createFactory();
667         if (mComponentFactory == nullptr) {
668             ALOGD("could not create factory in %s", libPath.c_str());
669             mInit = C2_NO_MEMORY;
670         } else {
671             mInit = C2_OK;
672         }
673     }
674     if (mInit != C2_OK) {
675         return mInit;
676     }
677 
678     std::shared_ptr<C2ComponentInterface> intf;
679     c2_status_t res = createInterface(0, &intf);
680     if (res != C2_OK) {
681         ALOGD("failed to create interface: %d", res);
682         return mInit;
683     }
684 
685     std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
686     if (traits) {
687         if (alias != intf->getName()) {
688             ALOGV("%s is alias to %s", alias.c_str(), intf->getName().c_str());
689         }
690         traits->name = alias;
691         // TODO: get this from interface properly.
692         bool encoder = (traits->name.find("encoder") != std::string::npos);
693         uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
694                 : C2PortMimeConfig::input::PARAM_TYPE;
695         std::vector<std::unique_ptr<C2Param>> params;
696         res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
697         if (res != C2_OK) {
698             ALOGD("failed to query interface: %d", res);
699             return mInit;
700         }
701         if (params.size() != 1u) {
702             ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
703             return mInit;
704         }
705         C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
706         if (mediaTypeConfig == nullptr) {
707             ALOGD("failed to query media type");
708             return mInit;
709         }
710         traits->mediaType = mediaTypeConfig->m.value;
711         // TODO: get this properly.
712         traits->rank = 0x200;
713 
714         // TODO: define these values properly
715         bool decoder = (traits->name.find("decoder") != std::string::npos);
716         traits->kind =
717                 decoder ? C2Component::KIND_DECODER :
718                 encoder ? C2Component::KIND_ENCODER :
719                 C2Component::KIND_OTHER;
720         if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
721             traits->domain = C2Component::DOMAIN_AUDIO;
722         } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
723             traits->domain = C2Component::DOMAIN_VIDEO;
724         } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
725             traits->domain = C2Component::DOMAIN_IMAGE;
726         } else {
727             traits->domain = C2Component::DOMAIN_OTHER;
728         }
729     }
730     mTraits = traits;
731 
732     return mInit;
733 }
734 
~ComponentModule()735 C2PlatformComponentStore::ComponentModule::~ComponentModule() {
736     ALOGV("in %s", __func__);
737     if (destroyFactory && mComponentFactory) {
738         destroyFactory(mComponentFactory);
739     }
740     if (mLibHandle) {
741         ALOGV("unloading dll");
742         dlclose(mLibHandle);
743     }
744 }
745 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * interface,std::function<void (::C2ComponentInterface *)> deleter)746 c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
747         c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
748         std::function<void(::C2ComponentInterface*)> deleter) {
749     interface->reset();
750     if (mInit != C2_OK) {
751         return mInit;
752     }
753     std::shared_ptr<ComponentModule> module = shared_from_this();
754     c2_status_t res = mComponentFactory->createInterface(
755             id, interface, [module, deleter](C2ComponentInterface *p) mutable {
756                 // capture module so that we ensure we still have it while deleting interface
757                 deleter(p); // delete interface first
758                 module.reset(); // remove module ref (not technically needed)
759     });
760     return res;
761 }
762 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * component,std::function<void (::C2Component *)> deleter)763 c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
764         c2_node_id_t id, std::shared_ptr<C2Component> *component,
765         std::function<void(::C2Component*)> deleter) {
766     component->reset();
767     if (mInit != C2_OK) {
768         return mInit;
769     }
770     std::shared_ptr<ComponentModule> module = shared_from_this();
771     c2_status_t res = mComponentFactory->createComponent(
772             id, component, [module, deleter](C2Component *p) mutable {
773                 // capture module so that we ensure we still have it while deleting component
774                 deleter(p); // delete component first
775                 module.reset(); // remove module ref (not technically needed)
776     });
777     return res;
778 }
779 
getTraits()780 std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
781     std::unique_lock<std::recursive_mutex> lock(mLock);
782     return mTraits;
783 }
784 
C2PlatformComponentStore()785 C2PlatformComponentStore::C2PlatformComponentStore()
786     : mReflector(std::make_shared<C2ReflectorHelper>()),
787       mInterface(mReflector) {
788 
789     auto emplace = [this](const char *alias, const char *libPath) {
790         // ComponentLoader is neither copiable nor movable, so it must be
791         // constructed in-place. Now ComponentLoader takes two arguments in
792         // constructor, so we need to use piecewise_construct to achieve this
793         // behavior.
794         mComponents.emplace(
795                 std::piecewise_construct,
796                 std::forward_as_tuple(alias),
797                 std::forward_as_tuple(alias, libPath));
798         mComponentsList.emplace_back(alias);
799     };
800     // TODO: move this also into a .so so it can be updated
801     emplace("c2.android.avc.decoder", "libstagefright_soft_c2avcdec.so");
802     emplace("c2.android.avc.encoder", "libstagefright_soft_c2avcenc.so");
803     emplace("c2.android.aac.decoder", "libstagefright_soft_c2aacdec.so");
804     emplace("c2.android.aac.encoder", "libstagefright_soft_c2aacenc.so");
805     emplace("c2.android.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
806     emplace("c2.android.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
807     emplace("c2.android.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
808     emplace("c2.android.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
809     emplace("c2.android.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
810     emplace("c2.android.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
811     emplace("c2.android.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
812     emplace("c2.android.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
813     emplace("c2.android.h263.decoder", "libstagefright_soft_c2h263dec.so");
814     emplace("c2.android.h263.encoder", "libstagefright_soft_c2h263enc.so");
815     emplace("c2.android.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
816     emplace("c2.android.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
817     emplace("c2.android.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
818     emplace("c2.android.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
819     emplace("c2.android.opus.decoder", "libstagefright_soft_c2opusdec.so");
820     emplace("c2.android.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
821     emplace("c2.android.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
822     emplace("c2.android.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
823     emplace("c2.android.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
824     emplace("c2.android.raw.decoder", "libstagefright_soft_c2rawdec.so");
825     emplace("c2.android.flac.decoder", "libstagefright_soft_c2flacdec.so");
826     emplace("c2.android.flac.encoder", "libstagefright_soft_c2flacenc.so");
827     emplace("c2.android.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
828     emplace("c2.android.xaac.decoder", "libstagefright_soft_c2xaacdec.so");
829 
830     // "Aliases"
831     // TODO: use aliases proper from C2Component::Traits
832     emplace("OMX.google.h264.decoder", "libstagefright_soft_c2avcdec.so");
833     emplace("OMX.google.h264.encoder", "libstagefright_soft_c2avcenc.so");
834     emplace("OMX.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
835     emplace("OMX.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
836     emplace("OMX.google.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
837     emplace("OMX.google.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
838     emplace("OMX.google.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
839     emplace("OMX.google.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
840     emplace("OMX.google.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
841     emplace("OMX.google.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
842     emplace("OMX.google.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
843     emplace("OMX.google.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
844     emplace("OMX.google.h263.decoder", "libstagefright_soft_c2h263dec.so");
845     emplace("OMX.google.h263.encoder", "libstagefright_soft_c2h263enc.so");
846     emplace("OMX.google.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
847     emplace("OMX.google.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
848     emplace("OMX.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
849     emplace("OMX.google.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
850     emplace("OMX.google.opus.decoder", "libstagefright_soft_c2opusdec.so");
851     emplace("OMX.google.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
852     emplace("OMX.google.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
853     emplace("OMX.google.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
854     emplace("OMX.google.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
855     emplace("OMX.google.raw.decoder", "libstagefright_soft_c2rawdec.so");
856     emplace("OMX.google.flac.decoder", "libstagefright_soft_c2flacdec.so");
857     emplace("OMX.google.flac.encoder", "libstagefright_soft_c2flacenc.so");
858     emplace("OMX.google.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
859     emplace("OMX.google.xaac.decoder", "libstagefright_soft_c2xaacdec.so");
860 }
861 
copyBuffer(std::shared_ptr<C2GraphicBuffer> src,std::shared_ptr<C2GraphicBuffer> dst)862 c2_status_t C2PlatformComponentStore::copyBuffer(
863         std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
864     (void)src;
865     (void)dst;
866     return C2_OMITTED;
867 }
868 
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const869 c2_status_t C2PlatformComponentStore::query_sm(
870         const std::vector<C2Param*> &stackParams,
871         const std::vector<C2Param::Index> &heapParamIndices,
872         std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
873     return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
874 }
875 
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)876 c2_status_t C2PlatformComponentStore::config_sm(
877         const std::vector<C2Param*> &params,
878         std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
879     return mInterface.config(params, C2_MAY_BLOCK, failures);
880 }
881 
listComponents()882 std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
883     // This method SHALL return within 500ms.
884     std::vector<std::shared_ptr<const C2Component::Traits>> list;
885     for (const C2String &alias : mComponentsList) {
886         ComponentLoader &loader = mComponents.at(alias);
887         std::shared_ptr<ComponentModule> module;
888         c2_status_t res = loader.fetchModule(&module);
889         if (res == C2_OK) {
890             std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
891             if (traits) {
892                 list.push_back(traits);
893             }
894         }
895     }
896     return list;
897 }
898 
findComponent(C2String name,ComponentLoader ** loader)899 c2_status_t C2PlatformComponentStore::findComponent(C2String name, ComponentLoader **loader) {
900     *loader = nullptr;
901     auto pos = mComponents.find(name);
902     // TODO: check aliases
903     if (pos == mComponents.end()) {
904         return C2_NOT_FOUND;
905     }
906     *loader = &pos->second;
907     return C2_OK;
908 }
909 
createComponent(C2String name,std::shared_ptr<C2Component> * const component)910 c2_status_t C2PlatformComponentStore::createComponent(
911         C2String name, std::shared_ptr<C2Component> *const component) {
912     // This method SHALL return within 100ms.
913     component->reset();
914     ComponentLoader *loader;
915     c2_status_t res = findComponent(name, &loader);
916     if (res == C2_OK) {
917         std::shared_ptr<ComponentModule> module;
918         res = loader->fetchModule(&module);
919         if (res == C2_OK) {
920             // TODO: get a unique node ID
921             res = module->createComponent(0, component);
922         }
923     }
924     return res;
925 }
926 
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)927 c2_status_t C2PlatformComponentStore::createInterface(
928         C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
929     // This method SHALL return within 100ms.
930     interface->reset();
931     ComponentLoader *loader;
932     c2_status_t res = findComponent(name, &loader);
933     if (res == C2_OK) {
934         std::shared_ptr<ComponentModule> module;
935         res = loader->fetchModule(&module);
936         if (res == C2_OK) {
937             // TODO: get a unique node ID
938             res = module->createInterface(0, interface);
939         }
940     }
941     return res;
942 }
943 
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const944 c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
945         std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
946     return mInterface.querySupportedParams(params);
947 }
948 
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const949 c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
950         std::vector<C2FieldSupportedValuesQuery> &fields) const {
951     return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
952 }
953 
getName() const954 C2String C2PlatformComponentStore::getName() const {
955     return "android.componentStore.platform";
956 }
957 
getParamReflector() const958 std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
959     return mReflector;
960 }
961 
GetCodec2PlatformComponentStore()962 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
963     static std::mutex mutex;
964     static std::weak_ptr<C2ComponentStore> platformStore;
965     std::lock_guard<std::mutex> lock(mutex);
966     std::shared_ptr<C2ComponentStore> store = platformStore.lock();
967     if (store == nullptr) {
968         store = std::make_shared<C2PlatformComponentStore>();
969         platformStore = store;
970     }
971     return store;
972 }
973 
974 } // namespace android
975