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         return C2_NOT_FOUND;
114     }
115     if (*allocator == nullptr) {
116         return C2_NO_MEMORY;
117     }
118     return C2_OK;
119 }
120 
121 namespace {
122 
123 std::mutex gIonAllocatorMutex;
124 std::weak_ptr<C2AllocatorIon> gIonAllocator;
125 
UseComponentStoreForIonAllocator(const std::shared_ptr<C2AllocatorIon> allocator,std::shared_ptr<C2ComponentStore> store)126 void UseComponentStoreForIonAllocator(
127         const std::shared_ptr<C2AllocatorIon> allocator,
128         std::shared_ptr<C2ComponentStore> store) {
129     C2AllocatorIon::UsageMapperFn mapper;
130     uint64_t minUsage = 0;
131     uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected;
132     size_t blockSize = getpagesize();
133 
134     // query min and max usage as well as block size via supported values
135     C2StoreIonUsageInfo usageInfo;
136     std::vector<C2FieldSupportedValuesQuery> query = {
137         C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.usage)),
138         C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.capacity)),
139     };
140     c2_status_t res = store->querySupportedValues_sm(query);
141     if (res == C2_OK) {
142         if (query[0].status == C2_OK) {
143             const C2FieldSupportedValues &fsv = query[0].values;
144             if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) {
145                 minUsage = fsv.values[0].u64;
146                 maxUsage = 0;
147                 for (C2Value::Primitive v : fsv.values) {
148                     maxUsage |= v.u64;
149                 }
150             }
151         }
152         if (query[1].status == C2_OK) {
153             const C2FieldSupportedValues &fsv = query[1].values;
154             if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) {
155                 blockSize = fsv.range.step.u32;
156             }
157         }
158 
159         mapper = [store](C2MemoryUsage usage, size_t capacity,
160                          size_t *align, unsigned *heapMask, unsigned *flags) -> c2_status_t {
161             if (capacity > UINT32_MAX) {
162                 return C2_BAD_VALUE;
163             }
164             C2StoreIonUsageInfo usageInfo = { usage.expected, capacity };
165             std::vector<std::unique_ptr<C2SettingResult>> failures; // TODO: remove
166             c2_status_t res = store->config_sm({&usageInfo}, &failures);
167             if (res == C2_OK) {
168                 *align = usageInfo.minAlignment;
169                 *heapMask = usageInfo.heapMask;
170                 *flags = usageInfo.allocFlags;
171             }
172             return res;
173         };
174     }
175 
176     allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize);
177 }
178 
179 }
180 
setComponentStore(std::shared_ptr<C2ComponentStore> store)181 void C2PlatformAllocatorStoreImpl::setComponentStore(std::shared_ptr<C2ComponentStore> store) {
182     // technically this set lock is not needed, but is here for safety in case we add more
183     // getter orders
184     std::lock_guard<std::mutex> lock(_mComponentStoreSetLock);
185     {
186         std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
187         _mComponentStore = store;
188     }
189     std::shared_ptr<C2AllocatorIon> allocator;
190     {
191         std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
192         allocator = gIonAllocator.lock();
193     }
194     if (allocator) {
195         UseComponentStoreForIonAllocator(allocator, store);
196     }
197 }
198 
fetchIonAllocator()199 std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
200     std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
201     std::shared_ptr<C2AllocatorIon> allocator = gIonAllocator.lock();
202     if (allocator == nullptr) {
203         std::shared_ptr<C2ComponentStore> componentStore;
204         {
205             std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
206             componentStore = _mComponentStore;
207         }
208         allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
209         UseComponentStoreForIonAllocator(allocator, componentStore);
210         gIonAllocator = allocator;
211     }
212     return allocator;
213 }
214 
fetchGrallocAllocator()215 std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
216     static std::mutex mutex;
217     static std::weak_ptr<C2Allocator> grallocAllocator;
218     std::lock_guard<std::mutex> lock(mutex);
219     std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
220     if (allocator == nullptr) {
221         allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
222         grallocAllocator = allocator;
223     }
224     return allocator;
225 }
226 
fetchBufferQueueAllocator()227 std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBufferQueueAllocator() {
228     static std::mutex mutex;
229     static std::weak_ptr<C2Allocator> grallocAllocator;
230     std::lock_guard<std::mutex> lock(mutex);
231     std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
232     if (allocator == nullptr) {
233         allocator = std::make_shared<C2AllocatorGralloc>(
234                 C2PlatformAllocatorStore::BUFFERQUEUE, true);
235         grallocAllocator = allocator;
236     }
237     return allocator;
238 }
239 
240 namespace {
241     std::mutex gPreferredComponentStoreMutex;
242     std::shared_ptr<C2ComponentStore> gPreferredComponentStore;
243 
244     std::mutex gPlatformAllocatorStoreMutex;
245     std::weak_ptr<C2PlatformAllocatorStoreImpl> gPlatformAllocatorStore;
246 }
247 
GetCodec2PlatformAllocatorStore()248 std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
249     std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
250     std::shared_ptr<C2PlatformAllocatorStoreImpl> store = gPlatformAllocatorStore.lock();
251     if (store == nullptr) {
252         store = std::make_shared<C2PlatformAllocatorStoreImpl>();
253         store->setComponentStore(GetPreferredCodec2ComponentStore());
254         gPlatformAllocatorStore = store;
255     }
256     return store;
257 }
258 
SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore)259 void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore) {
260     static std::mutex mutex;
261     std::lock_guard<std::mutex> lock(mutex); // don't interleve set-s
262 
263     // update preferred store
264     {
265         std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
266         gPreferredComponentStore = componentStore;
267     }
268 
269     // update platform allocator's store as well if it is alive
270     std::shared_ptr<C2PlatformAllocatorStoreImpl> allocatorStore;
271     {
272         std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
273         allocatorStore = gPlatformAllocatorStore.lock();
274     }
275     if (allocatorStore) {
276         allocatorStore->setComponentStore(componentStore);
277     }
278 }
279 
GetPreferredCodec2ComponentStore()280 std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore() {
281     std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
282     return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore();
283 }
284 
285 namespace {
286 
287 class _C2BlockPoolCache {
288 public:
_C2BlockPoolCache()289     _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
290 
_createBlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,C2BlockPool::local_id_t poolId,std::shared_ptr<C2BlockPool> * pool)291     c2_status_t _createBlockPool(
292             C2PlatformAllocatorStore::id_t allocatorId,
293             std::shared_ptr<const C2Component> component,
294             C2BlockPool::local_id_t poolId,
295             std::shared_ptr<C2BlockPool> *pool) {
296         std::shared_ptr<C2AllocatorStore> allocatorStore =
297                 GetCodec2PlatformAllocatorStore();
298         std::shared_ptr<C2Allocator> allocator;
299         c2_status_t res = C2_NOT_FOUND;
300 
301         switch(allocatorId) {
302             case C2PlatformAllocatorStore::ION:
303             case C2AllocatorStore::DEFAULT_LINEAR:
304                 res = allocatorStore->fetchAllocator(
305                         C2AllocatorStore::DEFAULT_LINEAR, &allocator);
306                 if (res == C2_OK) {
307                     std::shared_ptr<C2BlockPool> ptr =
308                             std::make_shared<C2PooledBlockPool>(
309                                     allocator, poolId);
310                     *pool = ptr;
311                     mBlockPools[poolId] = ptr;
312                     mComponents[poolId] = component;
313                 }
314                 break;
315             case C2PlatformAllocatorStore::GRALLOC:
316             case C2AllocatorStore::DEFAULT_GRAPHIC:
317                 res = allocatorStore->fetchAllocator(
318                         C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
319                 if (res == C2_OK) {
320                     std::shared_ptr<C2BlockPool> ptr =
321                         std::make_shared<C2PooledBlockPool>(allocator, poolId);
322                     *pool = ptr;
323                     mBlockPools[poolId] = ptr;
324                     mComponents[poolId] = component;
325                 }
326                 break;
327             case C2PlatformAllocatorStore::BUFFERQUEUE:
328                 res = allocatorStore->fetchAllocator(
329                         C2PlatformAllocatorStore::BUFFERQUEUE, &allocator);
330                 if (res == C2_OK) {
331                     std::shared_ptr<C2BlockPool> ptr =
332                             std::make_shared<C2BufferQueueBlockPool>(
333                                     allocator, poolId);
334                     *pool = ptr;
335                     mBlockPools[poolId] = ptr;
336                     mComponents[poolId] = component;
337                 }
338                 break;
339             default:
340                 // Try to create block pool from platform store plugins.
341                 std::shared_ptr<C2BlockPool> ptr;
342                 res = C2PlatformStorePluginLoader::GetInstance()->createBlockPool(
343                         allocatorId, poolId, &ptr);
344                 if (res == C2_OK) {
345                     *pool = ptr;
346                     mBlockPools[poolId] = ptr;
347                     mComponents[poolId] = component;
348                 }
349                 break;
350         }
351         return res;
352     }
353 
createBlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)354     c2_status_t createBlockPool(
355             C2PlatformAllocatorStore::id_t allocatorId,
356             std::shared_ptr<const C2Component> component,
357             std::shared_ptr<C2BlockPool> *pool) {
358         return _createBlockPool(allocatorId, component, mBlockPoolSeqId++, pool);
359     }
360 
getBlockPool(C2BlockPool::local_id_t blockPoolId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)361     bool getBlockPool(
362             C2BlockPool::local_id_t blockPoolId,
363             std::shared_ptr<const C2Component> component,
364             std::shared_ptr<C2BlockPool> *pool) {
365         // TODO: use one iterator for multiple blockpool type scalability.
366         std::shared_ptr<C2BlockPool> ptr;
367         auto it = mBlockPools.find(blockPoolId);
368         if (it != mBlockPools.end()) {
369             ptr = it->second.lock();
370             if (!ptr) {
371                 mBlockPools.erase(it);
372                 mComponents.erase(blockPoolId);
373             } else {
374                 auto found = mComponents.find(blockPoolId);
375                 if (component == found->second.lock()) {
376                     *pool = ptr;
377                     return true;
378                 }
379             }
380         }
381         return false;
382     }
383 
384 private:
385     C2BlockPool::local_id_t mBlockPoolSeqId;
386 
387     std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
388     std::map<C2BlockPool::local_id_t, std::weak_ptr<const C2Component>> mComponents;
389 };
390 
391 static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
392     std::make_unique<_C2BlockPoolCache>();
393 static std::mutex sBlockPoolCacheMutex;
394 
395 } // anynymous namespace
396 
GetCodec2BlockPool(C2BlockPool::local_id_t id,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)397 c2_status_t GetCodec2BlockPool(
398         C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
399         std::shared_ptr<C2BlockPool> *pool) {
400     pool->reset();
401     std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
402     std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
403     std::shared_ptr<C2Allocator> allocator;
404     c2_status_t res = C2_NOT_FOUND;
405 
406     if (id >= C2BlockPool::PLATFORM_START) {
407         if (sBlockPoolCache->getBlockPool(id, component, pool)) {
408             return C2_OK;
409         }
410     }
411 
412     switch (id) {
413     case C2BlockPool::BASIC_LINEAR:
414         res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
415         if (res == C2_OK) {
416             *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
417         }
418         break;
419     case C2BlockPool::BASIC_GRAPHIC:
420         res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
421         if (res == C2_OK) {
422             *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
423         }
424         break;
425     // TODO: remove this. this is temporary
426     case C2BlockPool::PLATFORM_START:
427         res = sBlockPoolCache->_createBlockPool(
428                 C2PlatformAllocatorStore::BUFFERQUEUE, component, id, pool);
429         break;
430     default:
431         break;
432     }
433     return res;
434 }
435 
CreateCodec2BlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)436 c2_status_t CreateCodec2BlockPool(
437         C2PlatformAllocatorStore::id_t allocatorId,
438         std::shared_ptr<const C2Component> component,
439         std::shared_ptr<C2BlockPool> *pool) {
440     pool->reset();
441 
442     std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
443     return sBlockPoolCache->createBlockPool(allocatorId, component, pool);
444 }
445 
446 class C2PlatformComponentStore : public C2ComponentStore {
447 public:
448     virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
449     virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
450     virtual C2String getName() const override;
451     virtual c2_status_t querySupportedValues_sm(
452             std::vector<C2FieldSupportedValuesQuery> &fields) const override;
453     virtual c2_status_t querySupportedParams_nb(
454             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override;
455     virtual c2_status_t query_sm(
456             const std::vector<C2Param*> &stackParams,
457             const std::vector<C2Param::Index> &heapParamIndices,
458             std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
459     virtual c2_status_t createInterface(
460             C2String name, std::shared_ptr<C2ComponentInterface> *const interface) override;
461     virtual c2_status_t createComponent(
462             C2String name, std::shared_ptr<C2Component> *const component) override;
463     virtual c2_status_t copyBuffer(
464             std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) override;
465     virtual c2_status_t config_sm(
466             const std::vector<C2Param*> &params,
467             std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
468     C2PlatformComponentStore();
469 
470     virtual ~C2PlatformComponentStore() override = default;
471 
472 private:
473 
474     /**
475      * An object encapsulating a loaded component module.
476      *
477      * \todo provide a way to add traits to known components here to avoid loading the .so-s
478      * for listComponents
479      */
480     struct ComponentModule : public C2ComponentFactory,
481             public std::enable_shared_from_this<ComponentModule> {
482         virtual c2_status_t createComponent(
483                 c2_node_id_t id, std::shared_ptr<C2Component> *component,
484                 ComponentDeleter deleter = std::default_delete<C2Component>()) override;
485         virtual c2_status_t createInterface(
486                 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
487                 InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;
488 
489         /**
490          * \returns the traits of the component in this module.
491          */
492         std::shared_ptr<const C2Component::Traits> getTraits();
493 
494         /**
495          * Creates an uninitialized component module.
496          *
497          * \param name[in]  component name.
498          *
499          * \note Only used by ComponentLoader.
500          */
ComponentModuleandroid::C2PlatformComponentStore::ComponentModule501         ComponentModule()
502             : mInit(C2_NO_INIT),
503               mLibHandle(nullptr),
504               createFactory(nullptr),
505               destroyFactory(nullptr),
506               mComponentFactory(nullptr) {
507         }
508 
509         /**
510          * Initializes a component module with a given library path. Must be called exactly once.
511          *
512          * \note Only used by ComponentLoader.
513          *
514          * \param libPath[in] library path (or name)
515          *
516          * \retval C2_OK        the component module has been successfully loaded
517          * \retval C2_NO_MEMORY not enough memory to loading the component module
518          * \retval C2_NOT_FOUND could not locate the component module
519          * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
520          * \retval C2_REFUSED   permission denied to load the component module (unexpected)
521          * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
522          */
523         c2_status_t init(std::string libPath);
524 
525         virtual ~ComponentModule() override;
526 
527     protected:
528         std::recursive_mutex mLock; ///< lock protecting mTraits
529         std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
530 
531         c2_status_t mInit; ///< initialization result
532 
533         void *mLibHandle; ///< loaded library handle
534         C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
535         C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
536         C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
537     };
538 
539     /**
540      * An object encapsulating a loadable component module.
541      *
542      * \todo make this also work for enumerations
543      */
544     struct ComponentLoader {
545         /**
546          * Load the component module.
547          *
548          * This method simply returns the component module if it is already currently loaded, or
549          * attempts to load it if it is not.
550          *
551          * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
552          *                    This will be nullptr on error.
553          *
554          * \retval C2_OK        the component module has been successfully loaded
555          * \retval C2_NO_MEMORY not enough memory to loading the component module
556          * \retval C2_NOT_FOUND could not locate the component module
557          * \retval C2_CORRUPTED the component module could not be loaded
558          * \retval C2_REFUSED   permission denied to load the component module
559          */
fetchModuleandroid::C2PlatformComponentStore::ComponentLoader560         c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
561             c2_status_t res = C2_OK;
562             std::lock_guard<std::mutex> lock(mMutex);
563             std::shared_ptr<ComponentModule> localModule = mModule.lock();
564             if (localModule == nullptr) {
565                 localModule = std::make_shared<ComponentModule>();
566                 res = localModule->init(mLibPath);
567                 if (res == C2_OK) {
568                     mModule = localModule;
569                 }
570             }
571             *module = localModule;
572             return res;
573         }
574 
575         /**
576          * Creates a component loader for a specific library path (or name).
577          */
ComponentLoaderandroid::C2PlatformComponentStore::ComponentLoader578         ComponentLoader(std::string libPath)
579             : mLibPath(libPath) {}
580 
581     private:
582         std::mutex mMutex; ///< mutex guarding the module
583         std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
584         std::string mLibPath; ///< library path (or name)
585     };
586 
587     struct Interface : public C2InterfaceHelper {
588         std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
589 
Interfaceandroid::C2PlatformComponentStore::Interface590         Interface(std::shared_ptr<C2ReflectorHelper> reflector)
591             : C2InterfaceHelper(reflector) {
592             setDerivedInstance(this);
593 
594             struct Setter {
595                 static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
596                     me.set().heapMask = ~0;
597                     me.set().allocFlags = 0;
598                     me.set().minAlignment = 0;
599                     return C2R::Ok();
600                 }
601             };
602 
603             addParameter(
604                 DefineParam(mIonUsageInfo, "ion-usage")
605                 .withDefault(new C2StoreIonUsageInfo())
606                 .withFields({
607                     C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
608                     C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
609                     C2F(mIonUsageInfo, heapMask).any(),
610                     C2F(mIonUsageInfo, allocFlags).flags({}),
611                     C2F(mIonUsageInfo, minAlignment).equalTo(0)
612                 })
613                 .withSetter(Setter::setIonUsage)
614                 .build());
615         }
616     };
617 
618     /**
619      * Retrieves the component loader for a component.
620      *
621      * \return a non-ref-holding pointer to the component loader.
622      *
623      * \retval C2_OK        the component loader has been successfully retrieved
624      * \retval C2_NO_MEMORY not enough memory to locate the component loader
625      * \retval C2_NOT_FOUND could not locate the component to be loaded
626      * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
627      *                      corrupted (this can happen if the name does not refer to an already
628      *                      identified component but some components could not be loaded due to
629      *                      bad library)
630      * \retval C2_REFUSED   permission denied to find the component loader for the named component
631      *                      (this can happen if the name does not refer to an already identified
632      *                      component but some components could not be loaded due to lack of
633      *                      permissions)
634      */
635     c2_status_t findComponent(C2String name, ComponentLoader **loader);
636 
637     std::map<C2String, ComponentLoader> mComponents; ///< list of components
638     std::shared_ptr<C2ReflectorHelper> mReflector;
639     Interface mInterface;
640 };
641 
init(std::string libPath)642 c2_status_t C2PlatformComponentStore::ComponentModule::init(std::string libPath) {
643     ALOGV("in %s", __func__);
644     ALOGV("loading dll");
645     mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
646     if (mLibHandle == nullptr) {
647         // could be access/symbol or simply not being there
648         ALOGD("could not dlopen %s: %s", libPath.c_str(), dlerror());
649         mInit = C2_CORRUPTED;
650     } else {
651         createFactory =
652             (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
653         destroyFactory =
654             (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
655 
656         mComponentFactory = createFactory();
657         if (mComponentFactory == nullptr) {
658             ALOGD("could not create factory in %s", libPath.c_str());
659             mInit = C2_NO_MEMORY;
660         } else {
661             mInit = C2_OK;
662         }
663     }
664     return mInit;
665 }
666 
~ComponentModule()667 C2PlatformComponentStore::ComponentModule::~ComponentModule() {
668     ALOGV("in %s", __func__);
669     if (destroyFactory && mComponentFactory) {
670         destroyFactory(mComponentFactory);
671     }
672     if (mLibHandle) {
673         ALOGV("unloading dll");
674         dlclose(mLibHandle);
675     }
676 }
677 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * interface,std::function<void (::C2ComponentInterface *)> deleter)678 c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
679         c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
680         std::function<void(::C2ComponentInterface*)> deleter) {
681     interface->reset();
682     if (mInit != C2_OK) {
683         return mInit;
684     }
685     std::shared_ptr<ComponentModule> module = shared_from_this();
686     c2_status_t res = mComponentFactory->createInterface(
687             id, interface, [module, deleter](C2ComponentInterface *p) mutable {
688                 // capture module so that we ensure we still have it while deleting interface
689                 deleter(p); // delete interface first
690                 module.reset(); // remove module ref (not technically needed)
691     });
692     return res;
693 }
694 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * component,std::function<void (::C2Component *)> deleter)695 c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
696         c2_node_id_t id, std::shared_ptr<C2Component> *component,
697         std::function<void(::C2Component*)> deleter) {
698     component->reset();
699     if (mInit != C2_OK) {
700         return mInit;
701     }
702     std::shared_ptr<ComponentModule> module = shared_from_this();
703     c2_status_t res = mComponentFactory->createComponent(
704             id, component, [module, deleter](C2Component *p) mutable {
705                 // capture module so that we ensure we still have it while deleting component
706                 deleter(p); // delete component first
707                 module.reset(); // remove module ref (not technically needed)
708     });
709     return res;
710 }
711 
getTraits()712 std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
713     std::unique_lock<std::recursive_mutex> lock(mLock);
714     if (!mTraits) {
715         std::shared_ptr<C2ComponentInterface> intf;
716         c2_status_t res = createInterface(0, &intf);
717         if (res != C2_OK) {
718             ALOGD("failed to create interface: %d", res);
719             return nullptr;
720         }
721 
722         std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
723         if (traits) {
724             traits->name = intf->getName();
725             // TODO: get this from interface properly.
726             bool encoder = (traits->name.find("encoder") != std::string::npos);
727             uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
728                     : C2PortMimeConfig::input::PARAM_TYPE;
729             std::vector<std::unique_ptr<C2Param>> params;
730             res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
731             if (res != C2_OK) {
732                 ALOGD("failed to query interface: %d", res);
733                 return nullptr;
734             }
735             if (params.size() != 1u) {
736                 ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
737                 return nullptr;
738             }
739             C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
740             if (mediaTypeConfig == nullptr) {
741                 ALOGD("failed to query media type");
742                 return nullptr;
743             }
744             traits->mediaType = mediaTypeConfig->m.value;
745             // TODO: get this properly.
746             traits->rank = 0x200;
747 
748             // TODO: define these values properly
749             bool decoder = (traits->name.find("decoder") != std::string::npos);
750             traits->kind =
751                     decoder ? C2Component::KIND_DECODER :
752                     encoder ? C2Component::KIND_ENCODER :
753                     C2Component::KIND_OTHER;
754             if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
755                 traits->domain = C2Component::DOMAIN_AUDIO;
756             } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
757                 traits->domain = C2Component::DOMAIN_VIDEO;
758             } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
759                 traits->domain = C2Component::DOMAIN_IMAGE;
760             } else {
761                 traits->domain = C2Component::DOMAIN_OTHER;
762             }
763         }
764 
765         mTraits = traits;
766     }
767     return mTraits;
768 }
769 
C2PlatformComponentStore()770 C2PlatformComponentStore::C2PlatformComponentStore()
771     : mReflector(std::make_shared<C2ReflectorHelper>()),
772       mInterface(mReflector) {
773     // TODO: move this also into a .so so it can be updated
774     mComponents.emplace("c2.android.avc.decoder", "libstagefright_soft_c2avcdec.so");
775     mComponents.emplace("c2.android.avc.encoder", "libstagefright_soft_c2avcenc.so");
776     mComponents.emplace("c2.android.aac.decoder", "libstagefright_soft_c2aacdec.so");
777     mComponents.emplace("c2.android.aac.encoder", "libstagefright_soft_c2aacenc.so");
778     mComponents.emplace("c2.android.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
779     mComponents.emplace("c2.android.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
780     mComponents.emplace("c2.android.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
781     mComponents.emplace("c2.android.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
782     mComponents.emplace("c2.android.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
783     mComponents.emplace("c2.android.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
784     mComponents.emplace("c2.android.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
785     mComponents.emplace("c2.android.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
786     mComponents.emplace("c2.android.h263.decoder", "libstagefright_soft_c2h263dec.so");
787     mComponents.emplace("c2.android.h263.encoder", "libstagefright_soft_c2h263enc.so");
788     mComponents.emplace("c2.android.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
789     mComponents.emplace("c2.android.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
790     mComponents.emplace("c2.android.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
791     mComponents.emplace("c2.android.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
792     mComponents.emplace("c2.android.opus.decoder", "libstagefright_soft_c2opusdec.so");
793     mComponents.emplace("c2.android.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
794     mComponents.emplace("c2.android.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
795     mComponents.emplace("c2.android.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
796     mComponents.emplace("c2.android.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
797     mComponents.emplace("c2.android.raw.decoder", "libstagefright_soft_c2rawdec.so");
798     mComponents.emplace("c2.android.flac.decoder", "libstagefright_soft_c2flacdec.so");
799     mComponents.emplace("c2.android.flac.encoder", "libstagefright_soft_c2flacenc.so");
800     mComponents.emplace("c2.android.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
801     mComponents.emplace("c2.android.xaac.decoder", "libstagefright_soft_c2xaacdec.so");
802 }
803 
copyBuffer(std::shared_ptr<C2GraphicBuffer> src,std::shared_ptr<C2GraphicBuffer> dst)804 c2_status_t C2PlatformComponentStore::copyBuffer(
805         std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
806     (void)src;
807     (void)dst;
808     return C2_OMITTED;
809 }
810 
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const811 c2_status_t C2PlatformComponentStore::query_sm(
812         const std::vector<C2Param*> &stackParams,
813         const std::vector<C2Param::Index> &heapParamIndices,
814         std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
815     return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
816 }
817 
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)818 c2_status_t C2PlatformComponentStore::config_sm(
819         const std::vector<C2Param*> &params,
820         std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
821     return mInterface.config(params, C2_MAY_BLOCK, failures);
822 }
823 
listComponents()824 std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
825     // This method SHALL return within 500ms.
826     std::vector<std::shared_ptr<const C2Component::Traits>> list;
827     for (auto &it : mComponents) {
828         ComponentLoader &loader = it.second;
829         std::shared_ptr<ComponentModule> module;
830         c2_status_t res = loader.fetchModule(&module);
831         if (res == C2_OK) {
832             std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
833             if (traits) {
834                 list.push_back(traits);
835             }
836         }
837     }
838     return list;
839 }
840 
findComponent(C2String name,ComponentLoader ** loader)841 c2_status_t C2PlatformComponentStore::findComponent(C2String name, ComponentLoader **loader) {
842     *loader = nullptr;
843     auto pos = mComponents.find(name);
844     // TODO: check aliases
845     if (pos == mComponents.end()) {
846         return C2_NOT_FOUND;
847     }
848     *loader = &pos->second;
849     return C2_OK;
850 }
851 
createComponent(C2String name,std::shared_ptr<C2Component> * const component)852 c2_status_t C2PlatformComponentStore::createComponent(
853         C2String name, std::shared_ptr<C2Component> *const component) {
854     // This method SHALL return within 100ms.
855     component->reset();
856     ComponentLoader *loader;
857     c2_status_t res = findComponent(name, &loader);
858     if (res == C2_OK) {
859         std::shared_ptr<ComponentModule> module;
860         res = loader->fetchModule(&module);
861         if (res == C2_OK) {
862             // TODO: get a unique node ID
863             res = module->createComponent(0, component);
864         }
865     }
866     return res;
867 }
868 
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)869 c2_status_t C2PlatformComponentStore::createInterface(
870         C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
871     // This method SHALL return within 100ms.
872     interface->reset();
873     ComponentLoader *loader;
874     c2_status_t res = findComponent(name, &loader);
875     if (res == C2_OK) {
876         std::shared_ptr<ComponentModule> module;
877         res = loader->fetchModule(&module);
878         if (res == C2_OK) {
879             // TODO: get a unique node ID
880             res = module->createInterface(0, interface);
881         }
882     }
883     return res;
884 }
885 
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const886 c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
887         std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
888     return mInterface.querySupportedParams(params);
889 }
890 
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const891 c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
892         std::vector<C2FieldSupportedValuesQuery> &fields) const {
893     return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
894 }
895 
getName() const896 C2String C2PlatformComponentStore::getName() const {
897     return "android.componentStore.platform";
898 }
899 
getParamReflector() const900 std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
901     return mReflector;
902 }
903 
GetCodec2PlatformComponentStore()904 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
905     static std::mutex mutex;
906     static std::weak_ptr<C2ComponentStore> platformStore;
907     std::lock_guard<std::mutex> lock(mutex);
908     std::shared_ptr<C2ComponentStore> store = platformStore.lock();
909     if (store == nullptr) {
910         store = std::make_shared<C2PlatformComponentStore>();
911         platformStore = store;
912     }
913     return store;
914 }
915 
916 } // namespace android
917