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