/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "C2Store" #define LOG_NDEBUG 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // getpagesize #include #include #include #ifdef __ANDROID_APEX__ #include #endif namespace android { /** * Returns the preferred component store in this process to access its interface. */ std::shared_ptr GetPreferredCodec2ComponentStore(); /** * The platform allocator store provides basic allocator-types for the framework based on ion and * gralloc. Allocators are not meant to be updatable. * * \todo Provide allocator based on ashmem * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags * \todo Make this allocator store extendable */ class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore { public: C2PlatformAllocatorStoreImpl(); virtual c2_status_t fetchAllocator( id_t id, std::shared_ptr *const allocator) override; virtual std::vector> listAllocators_nb() const override { return std::vector>(); /// \todo } virtual C2String getName() const override { return "android.allocator-store"; } void setComponentStore(std::shared_ptr store); ~C2PlatformAllocatorStoreImpl() override = default; private: /// returns a shared-singleton blob allocator (gralloc-backed) std::shared_ptr fetchBlobAllocator(); /// returns a shared-singleton ion allocator std::shared_ptr fetchIonAllocator(); std::shared_ptr fetchDmaBufAllocator(); /// returns a shared-singleton gralloc allocator std::shared_ptr fetchGrallocAllocator(); /// returns a shared-singleton bufferqueue supporting gralloc allocator std::shared_ptr fetchBufferQueueAllocator(); /// component store to use std::mutex _mComponentStoreSetLock; // protects the entire updating _mComponentStore and its // dependencies std::mutex _mComponentStoreReadLock; // must protect only read/write of _mComponentStore std::shared_ptr _mComponentStore; }; C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() { } static bool using_ion(void) { static int cached_result = []()->int { struct stat buffer; int ret = (stat("/dev/ion", &buffer) == 0); if (property_get_int32("debug.c2.use_dmabufheaps", 0)) { /* * Double check that the system heap is present so we * can gracefully fail back to ION if we cannot satisfy * the override */ ret = (stat("/dev/dma_heap/system", &buffer) != 0); if (ret) ALOGE("debug.c2.use_dmabufheaps set, but no system heap. Ignoring override!"); else ALOGD("debug.c2.use_dmabufheaps set, forcing DMABUF Heaps"); } if (ret) ALOGD("Using ION\n"); else ALOGD("Using DMABUF Heaps\n"); return ret; }(); return (cached_result == 1); } c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator( id_t id, std::shared_ptr *const allocator) { allocator->reset(); if (id == C2AllocatorStore::DEFAULT_LINEAR) { id = GetPreferredLinearAllocatorId(GetCodec2PoolMask()); } switch (id) { // TODO: should we implement a generic registry for all, and use that? case C2PlatformAllocatorStore::ION: /* also ::DMABUFHEAP */ if (using_ion()) *allocator = fetchIonAllocator(); else *allocator = fetchDmaBufAllocator(); break; case C2PlatformAllocatorStore::GRALLOC: case C2AllocatorStore::DEFAULT_GRAPHIC: *allocator = fetchGrallocAllocator(); break; case C2PlatformAllocatorStore::BUFFERQUEUE: *allocator = fetchBufferQueueAllocator(); break; case C2PlatformAllocatorStore::BLOB: *allocator = fetchBlobAllocator(); break; default: // Try to create allocator from platform store plugins. c2_status_t res = C2PlatformStorePluginLoader::GetInstance()->createAllocator(id, allocator); if (res != C2_OK) { return res; } break; } if (*allocator == nullptr) { return C2_NO_MEMORY; } return C2_OK; } namespace { std::mutex gIonAllocatorMutex; std::mutex gDmaBufAllocatorMutex; std::weak_ptr gIonAllocator; std::weak_ptr gDmaBufAllocator; void UseComponentStoreForIonAllocator( const std::shared_ptr allocator, std::shared_ptr store) { C2AllocatorIon::UsageMapperFn mapper; uint64_t minUsage = 0; uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected; size_t blockSize = getpagesize(); // query min and max usage as well as block size via supported values C2StoreIonUsageInfo usageInfo; std::vector query = { C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.usage)), C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.capacity)), }; c2_status_t res = store->querySupportedValues_sm(query); if (res == C2_OK) { if (query[0].status == C2_OK) { const C2FieldSupportedValues &fsv = query[0].values; if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) { minUsage = fsv.values[0].u64; maxUsage = 0; for (C2Value::Primitive v : fsv.values) { maxUsage |= v.u64; } } } if (query[1].status == C2_OK) { const C2FieldSupportedValues &fsv = query[1].values; if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) { blockSize = fsv.range.step.u32; } } mapper = [store](C2MemoryUsage usage, size_t capacity, size_t *align, unsigned *heapMask, unsigned *flags) -> c2_status_t { if (capacity > UINT32_MAX) { return C2_BAD_VALUE; } C2StoreIonUsageInfo usageInfo = { usage.expected, capacity }; std::vector> failures; // TODO: remove c2_status_t res = store->config_sm({&usageInfo}, &failures); if (res == C2_OK) { *align = usageInfo.minAlignment; *heapMask = usageInfo.heapMask; *flags = usageInfo.allocFlags; } return res; }; } allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize); } void UseComponentStoreForDmaBufAllocator(const std::shared_ptr allocator, std::shared_ptr store) { C2DmaBufAllocator::UsageMapperFn mapper; const size_t maxHeapNameLen = 128; uint64_t minUsage = 0; uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected; size_t blockSize = getpagesize(); // query min and max usage as well as block size via supported values std::unique_ptr usageInfo; usageInfo = C2StoreDmaBufUsageInfo::AllocUnique(maxHeapNameLen); std::vector query = { C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(*usageInfo, usageInfo->m.usage)), C2FieldSupportedValuesQuery::Possible( C2ParamField::Make(*usageInfo, usageInfo->m.capacity)), }; c2_status_t res = store->querySupportedValues_sm(query); if (res == C2_OK) { if (query[0].status == C2_OK) { const C2FieldSupportedValues& fsv = query[0].values; if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) { minUsage = fsv.values[0].u64; maxUsage = 0; for (C2Value::Primitive v : fsv.values) { maxUsage |= v.u64; } } } if (query[1].status == C2_OK) { const C2FieldSupportedValues& fsv = query[1].values; if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) { blockSize = fsv.range.step.u32; } } mapper = [store](C2MemoryUsage usage, size_t capacity, C2String* heapName, unsigned* flags) -> c2_status_t { if (capacity > UINT32_MAX) { return C2_BAD_VALUE; } std::unique_ptr usageInfo; usageInfo = C2StoreDmaBufUsageInfo::AllocUnique(maxHeapNameLen, usage.expected, capacity); std::vector> failures; // TODO: remove c2_status_t res = store->config_sm({&*usageInfo}, &failures); if (res == C2_OK) { *heapName = C2String(usageInfo->m.heapName); *flags = usageInfo->m.allocFlags; } return res; }; } allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize); } } void C2PlatformAllocatorStoreImpl::setComponentStore(std::shared_ptr store) { // technically this set lock is not needed, but is here for safety in case we add more // getter orders std::lock_guard lock(_mComponentStoreSetLock); { std::lock_guard lock(_mComponentStoreReadLock); _mComponentStore = store; } std::shared_ptr allocator; { std::lock_guard lock(gIonAllocatorMutex); allocator = gIonAllocator.lock(); } if (allocator) { UseComponentStoreForIonAllocator(allocator, store); } } std::shared_ptr C2PlatformAllocatorStoreImpl::fetchIonAllocator() { std::lock_guard lock(gIonAllocatorMutex); std::shared_ptr allocator = gIonAllocator.lock(); if (allocator == nullptr) { std::shared_ptr componentStore; { std::lock_guard lock(_mComponentStoreReadLock); componentStore = _mComponentStore; } allocator = std::make_shared(C2PlatformAllocatorStore::ION); UseComponentStoreForIonAllocator(allocator, componentStore); gIonAllocator = allocator; } return allocator; } std::shared_ptr C2PlatformAllocatorStoreImpl::fetchDmaBufAllocator() { std::lock_guard lock(gDmaBufAllocatorMutex); std::shared_ptr allocator = gDmaBufAllocator.lock(); if (allocator == nullptr) { std::shared_ptr componentStore; { std::lock_guard lock(_mComponentStoreReadLock); componentStore = _mComponentStore; } allocator = std::make_shared(C2PlatformAllocatorStore::DMABUFHEAP); UseComponentStoreForDmaBufAllocator(allocator, componentStore); gDmaBufAllocator = allocator; } return allocator; } std::shared_ptr C2PlatformAllocatorStoreImpl::fetchBlobAllocator() { static std::mutex mutex; static std::weak_ptr blobAllocator; std::lock_guard lock(mutex); std::shared_ptr allocator = blobAllocator.lock(); if (allocator == nullptr) { allocator = std::make_shared(C2PlatformAllocatorStore::BLOB); blobAllocator = allocator; } return allocator; } std::shared_ptr C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() { static std::mutex mutex; static std::weak_ptr grallocAllocator; std::lock_guard lock(mutex); std::shared_ptr allocator = grallocAllocator.lock(); if (allocator == nullptr) { allocator = std::make_shared(C2PlatformAllocatorStore::GRALLOC); grallocAllocator = allocator; } return allocator; } std::shared_ptr C2PlatformAllocatorStoreImpl::fetchBufferQueueAllocator() { static std::mutex mutex; static std::weak_ptr grallocAllocator; std::lock_guard lock(mutex); std::shared_ptr allocator = grallocAllocator.lock(); if (allocator == nullptr) { allocator = std::make_shared( C2PlatformAllocatorStore::BUFFERQUEUE, true); grallocAllocator = allocator; } return allocator; } namespace { std::mutex gPreferredComponentStoreMutex; std::shared_ptr gPreferredComponentStore; std::mutex gPlatformAllocatorStoreMutex; std::weak_ptr gPlatformAllocatorStore; } std::shared_ptr GetCodec2PlatformAllocatorStore() { std::lock_guard lock(gPlatformAllocatorStoreMutex); std::shared_ptr store = gPlatformAllocatorStore.lock(); if (store == nullptr) { store = std::make_shared(); store->setComponentStore(GetPreferredCodec2ComponentStore()); gPlatformAllocatorStore = store; } return store; } void SetPreferredCodec2ComponentStore(std::shared_ptr componentStore) { static std::mutex mutex; std::lock_guard lock(mutex); // don't interleve set-s // update preferred store { std::lock_guard lock(gPreferredComponentStoreMutex); gPreferredComponentStore = componentStore; } // update platform allocator's store as well if it is alive std::shared_ptr allocatorStore; { std::lock_guard lock(gPlatformAllocatorStoreMutex); allocatorStore = gPlatformAllocatorStore.lock(); } if (allocatorStore) { allocatorStore->setComponentStore(componentStore); } } std::shared_ptr GetPreferredCodec2ComponentStore() { std::lock_guard lock(gPreferredComponentStoreMutex); return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore(); } int GetCodec2PoolMask() { return property_get_int32( "debug.stagefright.c2-poolmask", 1 << C2PlatformAllocatorStore::ION | 1 << C2PlatformAllocatorStore::BUFFERQUEUE); } C2PlatformAllocatorStore::id_t GetPreferredLinearAllocatorId(int poolMask) { return ((poolMask >> C2PlatformAllocatorStore::BLOB) & 1) ? C2PlatformAllocatorStore::BLOB : C2PlatformAllocatorStore::ION; } namespace { class _C2BlockPoolCache { public: _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {} c2_status_t _createBlockPool( C2PlatformAllocatorStore::id_t allocatorId, std::vector> components, C2BlockPool::local_id_t poolId, std::shared_ptr *pool) { std::shared_ptr allocatorStore = GetCodec2PlatformAllocatorStore(); std::shared_ptr allocator; c2_status_t res = C2_NOT_FOUND; if (allocatorId == C2AllocatorStore::DEFAULT_LINEAR) { allocatorId = GetPreferredLinearAllocatorId(GetCodec2PoolMask()); } switch(allocatorId) { case C2PlatformAllocatorStore::ION: /* also ::DMABUFHEAP */ res = allocatorStore->fetchAllocator( C2PlatformAllocatorStore::ION, &allocator); if (res == C2_OK) { std::shared_ptr ptr = std::make_shared( allocator, poolId); *pool = ptr; mBlockPools[poolId] = ptr; mComponents[poolId].insert( mComponents[poolId].end(), components.begin(), components.end()); } break; case C2PlatformAllocatorStore::BLOB: res = allocatorStore->fetchAllocator( C2PlatformAllocatorStore::BLOB, &allocator); if (res == C2_OK) { std::shared_ptr ptr = std::make_shared( allocator, poolId); *pool = ptr; mBlockPools[poolId] = ptr; mComponents[poolId].insert( mComponents[poolId].end(), components.begin(), components.end()); } break; case C2PlatformAllocatorStore::GRALLOC: case C2AllocatorStore::DEFAULT_GRAPHIC: res = allocatorStore->fetchAllocator( C2AllocatorStore::DEFAULT_GRAPHIC, &allocator); if (res == C2_OK) { std::shared_ptr ptr = std::make_shared(allocator, poolId); *pool = ptr; mBlockPools[poolId] = ptr; mComponents[poolId].insert( mComponents[poolId].end(), components.begin(), components.end()); } break; case C2PlatformAllocatorStore::BUFFERQUEUE: res = allocatorStore->fetchAllocator( C2PlatformAllocatorStore::BUFFERQUEUE, &allocator); if (res == C2_OK) { std::shared_ptr ptr = std::make_shared( allocator, poolId); *pool = ptr; mBlockPools[poolId] = ptr; mComponents[poolId].insert( mComponents[poolId].end(), components.begin(), components.end()); } break; default: // Try to create block pool from platform store plugins. std::shared_ptr ptr; res = C2PlatformStorePluginLoader::GetInstance()->createBlockPool( allocatorId, poolId, &ptr); if (res == C2_OK) { *pool = ptr; mBlockPools[poolId] = ptr; mComponents[poolId].insert( mComponents[poolId].end(), components.begin(), components.end()); } break; } return res; } c2_status_t createBlockPool( C2PlatformAllocatorStore::id_t allocatorId, std::vector> components, std::shared_ptr *pool) { return _createBlockPool(allocatorId, components, mBlockPoolSeqId++, pool); } bool getBlockPool( C2BlockPool::local_id_t blockPoolId, std::shared_ptr component, std::shared_ptr *pool) { // TODO: use one iterator for multiple blockpool type scalability. std::shared_ptr ptr; auto it = mBlockPools.find(blockPoolId); if (it != mBlockPools.end()) { ptr = it->second.lock(); if (!ptr) { mBlockPools.erase(it); mComponents.erase(blockPoolId); } else { auto found = std::find_if( mComponents[blockPoolId].begin(), mComponents[blockPoolId].end(), [component](const std::weak_ptr &ptr) { return component == ptr.lock(); }); if (found != mComponents[blockPoolId].end()) { *pool = ptr; return true; } } } return false; } private: C2BlockPool::local_id_t mBlockPoolSeqId; std::map> mBlockPools; std::map>> mComponents; }; static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache = std::make_unique<_C2BlockPoolCache>(); static std::mutex sBlockPoolCacheMutex; } // anynymous namespace c2_status_t GetCodec2BlockPool( C2BlockPool::local_id_t id, std::shared_ptr component, std::shared_ptr *pool) { pool->reset(); std::lock_guard lock(sBlockPoolCacheMutex); std::shared_ptr allocatorStore = GetCodec2PlatformAllocatorStore(); std::shared_ptr allocator; c2_status_t res = C2_NOT_FOUND; if (id >= C2BlockPool::PLATFORM_START) { if (sBlockPoolCache->getBlockPool(id, component, pool)) { return C2_OK; } } switch (id) { case C2BlockPool::BASIC_LINEAR: res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator); if (res == C2_OK) { *pool = std::make_shared(allocator); } break; case C2BlockPool::BASIC_GRAPHIC: res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator); if (res == C2_OK) { *pool = std::make_shared(allocator); } break; // TODO: remove this. this is temporary case C2BlockPool::PLATFORM_START: res = sBlockPoolCache->_createBlockPool( C2PlatformAllocatorStore::BUFFERQUEUE, {component}, id, pool); break; default: break; } return res; } c2_status_t CreateCodec2BlockPool( C2PlatformAllocatorStore::id_t allocatorId, const std::vector> &components, std::shared_ptr *pool) { pool->reset(); std::lock_guard lock(sBlockPoolCacheMutex); return sBlockPoolCache->createBlockPool(allocatorId, components, pool); } c2_status_t CreateCodec2BlockPool( C2PlatformAllocatorStore::id_t allocatorId, std::shared_ptr component, std::shared_ptr *pool) { pool->reset(); std::lock_guard lock(sBlockPoolCacheMutex); return sBlockPoolCache->createBlockPool(allocatorId, {component}, pool); } class C2PlatformComponentStore : public C2ComponentStore { public: virtual std::vector> listComponents() override; virtual std::shared_ptr getParamReflector() const override; virtual C2String getName() const override; virtual c2_status_t querySupportedValues_sm( std::vector &fields) const override; virtual c2_status_t querySupportedParams_nb( std::vector> *const params) const override; virtual c2_status_t query_sm( const std::vector &stackParams, const std::vector &heapParamIndices, std::vector> *const heapParams) const override; virtual c2_status_t createInterface( C2String name, std::shared_ptr *const interface) override; virtual c2_status_t createComponent( C2String name, std::shared_ptr *const component) override; virtual c2_status_t copyBuffer( std::shared_ptr src, std::shared_ptr dst) override; virtual c2_status_t config_sm( const std::vector ¶ms, std::vector> *const failures) override; C2PlatformComponentStore(); // For testing only C2PlatformComponentStore( std::vector>); virtual ~C2PlatformComponentStore() override = default; private: /** * An object encapsulating a loaded component module. * * \todo provide a way to add traits to known components here to avoid loading the .so-s * for listComponents */ struct ComponentModule : public C2ComponentFactory, public std::enable_shared_from_this { virtual c2_status_t createComponent( c2_node_id_t id, std::shared_ptr *component, ComponentDeleter deleter = std::default_delete()) override; virtual c2_status_t createInterface( c2_node_id_t id, std::shared_ptr *interface, InterfaceDeleter deleter = std::default_delete()) override; /** * \returns the traits of the component in this module. */ std::shared_ptr getTraits(); /** * Creates an uninitialized component module. * * \param name[in] component name. * * \note Only used by ComponentLoader. */ ComponentModule() : mInit(C2_NO_INIT), mLibHandle(nullptr), createFactory(nullptr), destroyFactory(nullptr), mComponentFactory(nullptr) { } /** * Creates an uninitialized component module. * NOTE: For testing only * * \param name[in] component name. * * \note Only used by ComponentLoader. */ ComponentModule( C2ComponentFactory::CreateCodec2FactoryFunc createFactory, C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory) : mInit(C2_NO_INIT), mLibHandle(nullptr), createFactory(createFactory), destroyFactory(destroyFactory), mComponentFactory(nullptr) { } /** * Initializes a component module with a given library path. Must be called exactly once. * * \note Only used by ComponentLoader. * * \param libPath[in] library path * * \retval C2_OK the component module has been successfully loaded * \retval C2_NO_MEMORY not enough memory to loading the component module * \retval C2_NOT_FOUND could not locate the component module * \retval C2_CORRUPTED the component module could not be loaded (unexpected) * \retval C2_REFUSED permission denied to load the component module (unexpected) * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected) */ c2_status_t init(std::string libPath); virtual ~ComponentModule() override; protected: std::recursive_mutex mLock; ///< lock protecting mTraits std::shared_ptr mTraits; ///< cached component traits c2_status_t mInit; ///< initialization result void *mLibHandle; ///< loaded library handle C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function C2ComponentFactory *mComponentFactory; ///< loaded/created component factory }; /** * An object encapsulating a loadable component module. * * \todo make this also work for enumerations */ struct ComponentLoader { /** * Load the component module. * * This method simply returns the component module if it is already currently loaded, or * attempts to load it if it is not. * * \param module[out] pointer to the shared pointer where the loaded module shall be stored. * This will be nullptr on error. * * \retval C2_OK the component module has been successfully loaded * \retval C2_NO_MEMORY not enough memory to loading the component module * \retval C2_NOT_FOUND could not locate the component module * \retval C2_CORRUPTED the component module could not be loaded * \retval C2_REFUSED permission denied to load the component module */ c2_status_t fetchModule(std::shared_ptr *module) { c2_status_t res = C2_OK; std::lock_guard lock(mMutex); std::shared_ptr localModule = mModule.lock(); if (localModule == nullptr) { if(mCreateFactory) { // For testing only localModule = std::make_shared(mCreateFactory, mDestroyFactory); } else { localModule = std::make_shared(); } res = localModule->init(mLibPath); if (res == C2_OK) { mModule = localModule; } } *module = localModule; return res; } /** * Creates a component loader for a specific library path (or name). */ ComponentLoader(std::string libPath) : mLibPath(libPath) {} // For testing only ComponentLoader(std::tuple func) : mLibPath(std::get<0>(func)), mCreateFactory(std::get<1>(func)), mDestroyFactory(std::get<2>(func)) {} private: std::mutex mMutex; ///< mutex guarding the module std::weak_ptr mModule; ///< weak reference to the loaded module std::string mLibPath; ///< library path // For testing only C2ComponentFactory::CreateCodec2FactoryFunc mCreateFactory = nullptr; C2ComponentFactory::DestroyCodec2FactoryFunc mDestroyFactory = nullptr; }; struct Interface : public C2InterfaceHelper { std::shared_ptr mIonUsageInfo; std::shared_ptr mDmaBufUsageInfo; Interface(std::shared_ptr reflector) : C2InterfaceHelper(reflector) { setDerivedInstance(this); struct Setter { static C2R setIonUsage(bool /* mayBlock */, C2P &me) { #ifdef __ANDROID_APEX__ static int32_t defaultHeapMask = [] { int32_t heapmask = base::GetIntProperty( "ro.com.android.media.swcodec.ion.heapmask", int32_t(0xFFFFFFFF)); ALOGD("Default ION heapmask = %d", heapmask); return heapmask; }(); static int32_t defaultFlags = [] { int32_t flags = base::GetIntProperty( "ro.com.android.media.swcodec.ion.flags", 0); ALOGD("Default ION flags = %d", flags); return flags; }(); static uint32_t defaultAlign = [] { uint32_t align = base::GetUintProperty( "ro.com.android.media.swcodec.ion.align", 0u); ALOGD("Default ION align = %d", align); return align; }(); me.set().heapMask = defaultHeapMask; me.set().allocFlags = defaultFlags; me.set().minAlignment = defaultAlign; #else me.set().heapMask = ~0; me.set().allocFlags = 0; me.set().minAlignment = 0; #endif return C2R::Ok(); }; static C2R setDmaBufUsage(bool /* mayBlock */, C2P &me) { long long usage = (long long)me.get().m.usage; if (C2DmaBufAllocator::system_uncached_supported() && !(usage & (C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE))) { strncpy(me.set().m.heapName, "system-uncached", me.v.flexCount()); } else { strncpy(me.set().m.heapName, "system", me.v.flexCount()); } me.set().m.allocFlags = 0; return C2R::Ok(); }; }; addParameter( DefineParam(mIonUsageInfo, "ion-usage") .withDefault(new C2StoreIonUsageInfo()) .withFields({ C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}), C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024), C2F(mIonUsageInfo, heapMask).any(), C2F(mIonUsageInfo, allocFlags).flags({}), C2F(mIonUsageInfo, minAlignment).equalTo(0) }) .withSetter(Setter::setIonUsage) .build()); addParameter( DefineParam(mDmaBufUsageInfo, "dmabuf-usage") .withDefault(C2StoreDmaBufUsageInfo::AllocShared(0)) .withFields({ C2F(mDmaBufUsageInfo, m.usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}), C2F(mDmaBufUsageInfo, m.capacity).inRange(0, UINT32_MAX, 1024), C2F(mDmaBufUsageInfo, m.allocFlags).flags({}), C2F(mDmaBufUsageInfo, m.heapName).any(), }) .withSetter(Setter::setDmaBufUsage) .build()); } }; /** * Retrieves the component module for a component. * * \param module pointer to a shared_pointer where the component module will be stored on * success. * * \retval C2_OK the component loader has been successfully retrieved * \retval C2_NO_MEMORY not enough memory to locate the component loader * \retval C2_NOT_FOUND could not locate the component to be loaded * \retval C2_CORRUPTED the component loader could not be identified due to some modules being * corrupted (this can happen if the name does not refer to an already * identified component but some components could not be loaded due to * bad library) * \retval C2_REFUSED permission denied to find the component loader for the named component * (this can happen if the name does not refer to an already identified * component but some components could not be loaded due to lack of * permissions) */ c2_status_t findComponent(C2String name, std::shared_ptr *module); /** * Loads each component module and discover its contents. */ void visitComponents(); std::mutex mMutex; ///< mutex guarding the component lists during construction bool mVisited; ///< component modules visited std::map mComponents; ///< path -> component module std::map mComponentNameToPath; ///< name -> path std::vector> mComponentList; std::shared_ptr mReflector; Interface mInterface; // For testing only std::vector> mCodec2FactoryFuncs; }; c2_status_t C2PlatformComponentStore::ComponentModule::init( std::string libPath) { ALOGV("in %s", __func__); ALOGV("loading dll"); if(!createFactory) { mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE); LOG_ALWAYS_FATAL_IF(mLibHandle == nullptr, "could not dlopen %s: %s", libPath.c_str(), dlerror()); createFactory = (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory"); LOG_ALWAYS_FATAL_IF(createFactory == nullptr, "createFactory is null in %s", libPath.c_str()); destroyFactory = (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory"); LOG_ALWAYS_FATAL_IF(destroyFactory == nullptr, "destroyFactory is null in %s", libPath.c_str()); } mComponentFactory = createFactory(); if (mComponentFactory == nullptr) { ALOGD("could not create factory in %s", libPath.c_str()); mInit = C2_NO_MEMORY; } else { mInit = C2_OK; } if (mInit != C2_OK) { return mInit; } std::shared_ptr intf; c2_status_t res = createInterface(0, &intf); if (res != C2_OK) { ALOGD("failed to create interface: %d", res); return mInit; } std::shared_ptr traits(new (std::nothrow) C2Component::Traits); if (traits) { if (!C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf)) { ALOGD("Failed to fill traits from interface"); return mInit; } // TODO: get this properly from the store during emplace switch (traits->domain) { case C2Component::DOMAIN_AUDIO: traits->rank = 8; break; default: traits->rank = 512; } } mTraits = traits; return mInit; } C2PlatformComponentStore::ComponentModule::~ComponentModule() { ALOGV("in %s", __func__); if (destroyFactory && mComponentFactory) { destroyFactory(mComponentFactory); } if (mLibHandle) { ALOGV("unloading dll"); dlclose(mLibHandle); } } c2_status_t C2PlatformComponentStore::ComponentModule::createInterface( c2_node_id_t id, std::shared_ptr *interface, std::function deleter) { interface->reset(); if (mInit != C2_OK) { return mInit; } std::shared_ptr module = shared_from_this(); c2_status_t res = mComponentFactory->createInterface( id, interface, [module, deleter](C2ComponentInterface *p) mutable { // capture module so that we ensure we still have it while deleting interface deleter(p); // delete interface first module.reset(); // remove module ref (not technically needed) }); return res; } c2_status_t C2PlatformComponentStore::ComponentModule::createComponent( c2_node_id_t id, std::shared_ptr *component, std::function deleter) { component->reset(); if (mInit != C2_OK) { return mInit; } std::shared_ptr module = shared_from_this(); c2_status_t res = mComponentFactory->createComponent( id, component, [module, deleter](C2Component *p) mutable { // capture module so that we ensure we still have it while deleting component deleter(p); // delete component first module.reset(); // remove module ref (not technically needed) }); return res; } std::shared_ptr C2PlatformComponentStore::ComponentModule::getTraits() { std::unique_lock lock(mLock); return mTraits; } C2PlatformComponentStore::C2PlatformComponentStore() : mVisited(false), mReflector(std::make_shared()), mInterface(mReflector) { auto emplace = [this](const char *libPath) { mComponents.emplace(libPath, libPath); }; // TODO: move this also into a .so so it can be updated emplace("libcodec2_soft_aacdec.so"); emplace("libcodec2_soft_aacenc.so"); emplace("libcodec2_soft_amrnbdec.so"); emplace("libcodec2_soft_amrnbenc.so"); emplace("libcodec2_soft_amrwbdec.so"); emplace("libcodec2_soft_amrwbenc.so"); //emplace("libcodec2_soft_av1dec_aom.so"); // deprecated for the gav1 implementation emplace("libcodec2_soft_av1dec_gav1.so"); emplace("libcodec2_soft_avcdec.so"); emplace("libcodec2_soft_avcenc.so"); emplace("libcodec2_soft_flacdec.so"); emplace("libcodec2_soft_flacenc.so"); emplace("libcodec2_soft_g711alawdec.so"); emplace("libcodec2_soft_g711mlawdec.so"); emplace("libcodec2_soft_gsmdec.so"); emplace("libcodec2_soft_h263dec.so"); emplace("libcodec2_soft_h263enc.so"); emplace("libcodec2_soft_hevcdec.so"); emplace("libcodec2_soft_hevcenc.so"); emplace("libcodec2_soft_mp3dec.so"); emplace("libcodec2_soft_mpeg2dec.so"); emplace("libcodec2_soft_mpeg4dec.so"); emplace("libcodec2_soft_mpeg4enc.so"); emplace("libcodec2_soft_opusdec.so"); emplace("libcodec2_soft_opusenc.so"); emplace("libcodec2_soft_rawdec.so"); emplace("libcodec2_soft_vorbisdec.so"); emplace("libcodec2_soft_vp8dec.so"); emplace("libcodec2_soft_vp8enc.so"); emplace("libcodec2_soft_vp9dec.so"); emplace("libcodec2_soft_vp9enc.so"); } // For testing only C2PlatformComponentStore::C2PlatformComponentStore( std::vector> funcs) : mVisited(false), mReflector(std::make_shared()), mInterface(mReflector), mCodec2FactoryFuncs(funcs) { for(auto const& func: mCodec2FactoryFuncs) { mComponents.emplace(std::get<0>(func), func); } } c2_status_t C2PlatformComponentStore::copyBuffer( std::shared_ptr src, std::shared_ptr dst) { (void)src; (void)dst; return C2_OMITTED; } c2_status_t C2PlatformComponentStore::query_sm( const std::vector &stackParams, const std::vector &heapParamIndices, std::vector> *const heapParams) const { return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams); } c2_status_t C2PlatformComponentStore::config_sm( const std::vector ¶ms, std::vector> *const failures) { return mInterface.config(params, C2_MAY_BLOCK, failures); } void C2PlatformComponentStore::visitComponents() { std::lock_guard lock(mMutex); if (mVisited) { return; } for (auto &pathAndLoader : mComponents) { const C2String &path = pathAndLoader.first; ComponentLoader &loader = pathAndLoader.second; std::shared_ptr module; if (loader.fetchModule(&module) == C2_OK) { std::shared_ptr traits = module->getTraits(); if (traits) { mComponentList.push_back(traits); mComponentNameToPath.emplace(traits->name, path); for (const C2String &alias : traits->aliases) { mComponentNameToPath.emplace(alias, path); } } } } mVisited = true; } std::vector> C2PlatformComponentStore::listComponents() { // This method SHALL return within 500ms. visitComponents(); return mComponentList; } c2_status_t C2PlatformComponentStore::findComponent( C2String name, std::shared_ptr *module) { (*module).reset(); visitComponents(); auto pos = mComponentNameToPath.find(name); if (pos != mComponentNameToPath.end()) { return mComponents.at(pos->second).fetchModule(module); } return C2_NOT_FOUND; } c2_status_t C2PlatformComponentStore::createComponent( C2String name, std::shared_ptr *const component) { // This method SHALL return within 100ms. component->reset(); std::shared_ptr module; c2_status_t res = findComponent(name, &module); if (res == C2_OK) { // TODO: get a unique node ID res = module->createComponent(0, component); } return res; } c2_status_t C2PlatformComponentStore::createInterface( C2String name, std::shared_ptr *const interface) { // This method SHALL return within 100ms. interface->reset(); std::shared_ptr module; c2_status_t res = findComponent(name, &module); if (res == C2_OK) { // TODO: get a unique node ID res = module->createInterface(0, interface); } return res; } c2_status_t C2PlatformComponentStore::querySupportedParams_nb( std::vector> *const params) const { return mInterface.querySupportedParams(params); } c2_status_t C2PlatformComponentStore::querySupportedValues_sm( std::vector &fields) const { return mInterface.querySupportedValues(fields, C2_MAY_BLOCK); } C2String C2PlatformComponentStore::getName() const { return "android.componentStore.platform"; } std::shared_ptr C2PlatformComponentStore::getParamReflector() const { return mReflector; } std::shared_ptr GetCodec2PlatformComponentStore() { static std::mutex mutex; static std::weak_ptr platformStore; std::lock_guard lock(mutex); std::shared_ptr store = platformStore.lock(); if (store == nullptr) { store = std::make_shared(); platformStore = store; } return store; } // For testing only std::shared_ptr GetTestComponentStore( std::vector> funcs) { return std::shared_ptr(new C2PlatformComponentStore(funcs)); } } // namespace android