Home | History | Annotate | Download | only in vndk
      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 
     60     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 
     65     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 
     90 C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
     91 }
     92 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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:
    289     _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
    290 
    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 
    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 
    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 
    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 
    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          */
    501         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          */
    560         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          */
    578         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 
    590         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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    811 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 
    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 
    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 
    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 
    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 
    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 
    886 c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
    887         std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
    888     return mInterface.querySupportedParams(params);
    889 }
    890 
    891 c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
    892         std::vector<C2FieldSupportedValuesQuery> &fields) const {
    893     return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
    894 }
    895 
    896 C2String C2PlatformComponentStore::getName() const {
    897     return "android.componentStore.platform";
    898 }
    899 
    900 std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
    901     return mReflector;
    902 }
    903 
    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