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