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 // 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
UseComponentStoreForIonAllocator(const std::shared_ptr<C2AllocatorIon> allocator,std::shared_ptr<C2ComponentStore> store)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
setComponentStore(std::shared_ptr<C2ComponentStore> store)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
fetchIonAllocator()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
fetchGrallocAllocator()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
fetchBufferQueueAllocator()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
GetCodec2PlatformAllocatorStore()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
SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore)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
GetPreferredCodec2ComponentStore()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:
_C2BlockPoolCache()295 _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
296
_createBlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,C2BlockPool::local_id_t poolId,std::shared_ptr<C2BlockPool> * pool)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
createBlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)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
getBlockPool(C2BlockPool::local_id_t blockPoolId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)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
GetCodec2BlockPool(C2BlockPool::local_id_t id,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)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
CreateCodec2BlockPool(C2PlatformAllocatorStore::id_t allocatorId,std::shared_ptr<const C2Component> component,std::shared_ptr<C2BlockPool> * pool)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 */
ComponentModuleandroid::C2PlatformComponentStore::ComponentModule507 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 alias[in] module alias
521 * \param libPath[in] library path
522 *
523 * \retval C2_OK the component module has been successfully loaded
524 * \retval C2_NO_MEMORY not enough memory to loading the component module
525 * \retval C2_NOT_FOUND could not locate the component module
526 * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
527 * \retval C2_REFUSED permission denied to load the component module (unexpected)
528 * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
529 */
530 c2_status_t init(std::string alias, std::string libPath);
531
532 virtual ~ComponentModule() override;
533
534 protected:
535 std::recursive_mutex mLock; ///< lock protecting mTraits
536 std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
537
538 c2_status_t mInit; ///< initialization result
539
540 void *mLibHandle; ///< loaded library handle
541 C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
542 C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
543 C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
544 };
545
546 /**
547 * An object encapsulating a loadable component module.
548 *
549 * \todo make this also work for enumerations
550 */
551 struct ComponentLoader {
552 /**
553 * Load the component module.
554 *
555 * This method simply returns the component module if it is already currently loaded, or
556 * attempts to load it if it is not.
557 *
558 * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
559 * This will be nullptr on error.
560 *
561 * \retval C2_OK the component module has been successfully loaded
562 * \retval C2_NO_MEMORY not enough memory to loading the component module
563 * \retval C2_NOT_FOUND could not locate the component module
564 * \retval C2_CORRUPTED the component module could not be loaded
565 * \retval C2_REFUSED permission denied to load the component module
566 */
fetchModuleandroid::C2PlatformComponentStore::ComponentLoader567 c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
568 c2_status_t res = C2_OK;
569 std::lock_guard<std::mutex> lock(mMutex);
570 std::shared_ptr<ComponentModule> localModule = mModule.lock();
571 if (localModule == nullptr) {
572 localModule = std::make_shared<ComponentModule>();
573 res = localModule->init(mAlias, mLibPath);
574 if (res == C2_OK) {
575 mModule = localModule;
576 }
577 }
578 *module = localModule;
579 return res;
580 }
581
582 /**
583 * Creates a component loader for a specific library path (or name).
584 */
ComponentLoaderandroid::C2PlatformComponentStore::ComponentLoader585 ComponentLoader(std::string alias, std::string libPath)
586 : mAlias(alias), mLibPath(libPath) {}
587
588 private:
589 std::mutex mMutex; ///< mutex guarding the module
590 std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
591 std::string mAlias; ///< component alias
592 std::string mLibPath; ///< library path
593 };
594
595 struct Interface : public C2InterfaceHelper {
596 std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
597
Interfaceandroid::C2PlatformComponentStore::Interface598 Interface(std::shared_ptr<C2ReflectorHelper> reflector)
599 : C2InterfaceHelper(reflector) {
600 setDerivedInstance(this);
601
602 struct Setter {
603 static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
604 me.set().heapMask = ~0;
605 me.set().allocFlags = 0;
606 me.set().minAlignment = 0;
607 return C2R::Ok();
608 }
609 };
610
611 addParameter(
612 DefineParam(mIonUsageInfo, "ion-usage")
613 .withDefault(new C2StoreIonUsageInfo())
614 .withFields({
615 C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
616 C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
617 C2F(mIonUsageInfo, heapMask).any(),
618 C2F(mIonUsageInfo, allocFlags).flags({}),
619 C2F(mIonUsageInfo, minAlignment).equalTo(0)
620 })
621 .withSetter(Setter::setIonUsage)
622 .build());
623 }
624 };
625
626 /**
627 * Retrieves the component loader for a component.
628 *
629 * \return a non-ref-holding pointer to the component loader.
630 *
631 * \retval C2_OK the component loader has been successfully retrieved
632 * \retval C2_NO_MEMORY not enough memory to locate the component loader
633 * \retval C2_NOT_FOUND could not locate the component to be loaded
634 * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
635 * corrupted (this can happen if the name does not refer to an already
636 * identified component but some components could not be loaded due to
637 * bad library)
638 * \retval C2_REFUSED permission denied to find the component loader for the named component
639 * (this can happen if the name does not refer to an already identified
640 * component but some components could not be loaded due to lack of
641 * permissions)
642 */
643 c2_status_t findComponent(C2String name, ComponentLoader **loader);
644
645 std::map<C2String, ComponentLoader> mComponents; ///< map of name -> components
646 std::vector<C2String> mComponentsList; ///< list of components
647 std::shared_ptr<C2ReflectorHelper> mReflector;
648 Interface mInterface;
649 };
650
init(std::string alias,std::string libPath)651 c2_status_t C2PlatformComponentStore::ComponentModule::init(
652 std::string alias, std::string libPath) {
653 ALOGV("in %s", __func__);
654 ALOGV("loading dll");
655 mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
656 if (mLibHandle == nullptr) {
657 // could be access/symbol or simply not being there
658 ALOGD("could not dlopen %s: %s", libPath.c_str(), dlerror());
659 mInit = C2_CORRUPTED;
660 } else {
661 createFactory =
662 (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
663 destroyFactory =
664 (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
665
666 mComponentFactory = createFactory();
667 if (mComponentFactory == nullptr) {
668 ALOGD("could not create factory in %s", libPath.c_str());
669 mInit = C2_NO_MEMORY;
670 } else {
671 mInit = C2_OK;
672 }
673 }
674 if (mInit != C2_OK) {
675 return mInit;
676 }
677
678 std::shared_ptr<C2ComponentInterface> intf;
679 c2_status_t res = createInterface(0, &intf);
680 if (res != C2_OK) {
681 ALOGD("failed to create interface: %d", res);
682 return mInit;
683 }
684
685 std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
686 if (traits) {
687 if (alias != intf->getName()) {
688 ALOGV("%s is alias to %s", alias.c_str(), intf->getName().c_str());
689 }
690 traits->name = alias;
691 // TODO: get this from interface properly.
692 bool encoder = (traits->name.find("encoder") != std::string::npos);
693 uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
694 : C2PortMimeConfig::input::PARAM_TYPE;
695 std::vector<std::unique_ptr<C2Param>> params;
696 res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, ¶ms);
697 if (res != C2_OK) {
698 ALOGD("failed to query interface: %d", res);
699 return mInit;
700 }
701 if (params.size() != 1u) {
702 ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
703 return mInit;
704 }
705 C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
706 if (mediaTypeConfig == nullptr) {
707 ALOGD("failed to query media type");
708 return mInit;
709 }
710 traits->mediaType = mediaTypeConfig->m.value;
711 // TODO: get this properly.
712 traits->rank = 0x200;
713
714 // TODO: define these values properly
715 bool decoder = (traits->name.find("decoder") != std::string::npos);
716 traits->kind =
717 decoder ? C2Component::KIND_DECODER :
718 encoder ? C2Component::KIND_ENCODER :
719 C2Component::KIND_OTHER;
720 if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
721 traits->domain = C2Component::DOMAIN_AUDIO;
722 } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
723 traits->domain = C2Component::DOMAIN_VIDEO;
724 } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
725 traits->domain = C2Component::DOMAIN_IMAGE;
726 } else {
727 traits->domain = C2Component::DOMAIN_OTHER;
728 }
729 }
730 mTraits = traits;
731
732 return mInit;
733 }
734
~ComponentModule()735 C2PlatformComponentStore::ComponentModule::~ComponentModule() {
736 ALOGV("in %s", __func__);
737 if (destroyFactory && mComponentFactory) {
738 destroyFactory(mComponentFactory);
739 }
740 if (mLibHandle) {
741 ALOGV("unloading dll");
742 dlclose(mLibHandle);
743 }
744 }
745
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * interface,std::function<void (::C2ComponentInterface *)> deleter)746 c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
747 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
748 std::function<void(::C2ComponentInterface*)> deleter) {
749 interface->reset();
750 if (mInit != C2_OK) {
751 return mInit;
752 }
753 std::shared_ptr<ComponentModule> module = shared_from_this();
754 c2_status_t res = mComponentFactory->createInterface(
755 id, interface, [module, deleter](C2ComponentInterface *p) mutable {
756 // capture module so that we ensure we still have it while deleting interface
757 deleter(p); // delete interface first
758 module.reset(); // remove module ref (not technically needed)
759 });
760 return res;
761 }
762
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * component,std::function<void (::C2Component *)> deleter)763 c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
764 c2_node_id_t id, std::shared_ptr<C2Component> *component,
765 std::function<void(::C2Component*)> deleter) {
766 component->reset();
767 if (mInit != C2_OK) {
768 return mInit;
769 }
770 std::shared_ptr<ComponentModule> module = shared_from_this();
771 c2_status_t res = mComponentFactory->createComponent(
772 id, component, [module, deleter](C2Component *p) mutable {
773 // capture module so that we ensure we still have it while deleting component
774 deleter(p); // delete component first
775 module.reset(); // remove module ref (not technically needed)
776 });
777 return res;
778 }
779
getTraits()780 std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
781 std::unique_lock<std::recursive_mutex> lock(mLock);
782 return mTraits;
783 }
784
C2PlatformComponentStore()785 C2PlatformComponentStore::C2PlatformComponentStore()
786 : mReflector(std::make_shared<C2ReflectorHelper>()),
787 mInterface(mReflector) {
788
789 auto emplace = [this](const char *alias, const char *libPath) {
790 // ComponentLoader is neither copiable nor movable, so it must be
791 // constructed in-place. Now ComponentLoader takes two arguments in
792 // constructor, so we need to use piecewise_construct to achieve this
793 // behavior.
794 mComponents.emplace(
795 std::piecewise_construct,
796 std::forward_as_tuple(alias),
797 std::forward_as_tuple(alias, libPath));
798 mComponentsList.emplace_back(alias);
799 };
800 // TODO: move this also into a .so so it can be updated
801 emplace("c2.android.avc.decoder", "libstagefright_soft_c2avcdec.so");
802 emplace("c2.android.avc.encoder", "libstagefright_soft_c2avcenc.so");
803 emplace("c2.android.aac.decoder", "libstagefright_soft_c2aacdec.so");
804 emplace("c2.android.aac.encoder", "libstagefright_soft_c2aacenc.so");
805 emplace("c2.android.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
806 emplace("c2.android.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
807 emplace("c2.android.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
808 emplace("c2.android.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
809 emplace("c2.android.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
810 emplace("c2.android.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
811 emplace("c2.android.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
812 emplace("c2.android.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
813 emplace("c2.android.h263.decoder", "libstagefright_soft_c2h263dec.so");
814 emplace("c2.android.h263.encoder", "libstagefright_soft_c2h263enc.so");
815 emplace("c2.android.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
816 emplace("c2.android.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
817 emplace("c2.android.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
818 emplace("c2.android.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
819 emplace("c2.android.opus.decoder", "libstagefright_soft_c2opusdec.so");
820 emplace("c2.android.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
821 emplace("c2.android.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
822 emplace("c2.android.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
823 emplace("c2.android.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
824 emplace("c2.android.raw.decoder", "libstagefright_soft_c2rawdec.so");
825 emplace("c2.android.flac.decoder", "libstagefright_soft_c2flacdec.so");
826 emplace("c2.android.flac.encoder", "libstagefright_soft_c2flacenc.so");
827 emplace("c2.android.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
828 emplace("c2.android.xaac.decoder", "libstagefright_soft_c2xaacdec.so");
829
830 // "Aliases"
831 // TODO: use aliases proper from C2Component::Traits
832 emplace("OMX.google.h264.decoder", "libstagefright_soft_c2avcdec.so");
833 emplace("OMX.google.h264.encoder", "libstagefright_soft_c2avcenc.so");
834 emplace("OMX.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
835 emplace("OMX.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
836 emplace("OMX.google.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
837 emplace("OMX.google.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
838 emplace("OMX.google.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
839 emplace("OMX.google.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
840 emplace("OMX.google.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
841 emplace("OMX.google.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
842 emplace("OMX.google.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
843 emplace("OMX.google.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
844 emplace("OMX.google.h263.decoder", "libstagefright_soft_c2h263dec.so");
845 emplace("OMX.google.h263.encoder", "libstagefright_soft_c2h263enc.so");
846 emplace("OMX.google.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
847 emplace("OMX.google.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
848 emplace("OMX.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
849 emplace("OMX.google.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
850 emplace("OMX.google.opus.decoder", "libstagefright_soft_c2opusdec.so");
851 emplace("OMX.google.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
852 emplace("OMX.google.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
853 emplace("OMX.google.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
854 emplace("OMX.google.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
855 emplace("OMX.google.raw.decoder", "libstagefright_soft_c2rawdec.so");
856 emplace("OMX.google.flac.decoder", "libstagefright_soft_c2flacdec.so");
857 emplace("OMX.google.flac.encoder", "libstagefright_soft_c2flacenc.so");
858 emplace("OMX.google.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
859 emplace("OMX.google.xaac.decoder", "libstagefright_soft_c2xaacdec.so");
860 }
861
copyBuffer(std::shared_ptr<C2GraphicBuffer> src,std::shared_ptr<C2GraphicBuffer> dst)862 c2_status_t C2PlatformComponentStore::copyBuffer(
863 std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
864 (void)src;
865 (void)dst;
866 return C2_OMITTED;
867 }
868
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const869 c2_status_t C2PlatformComponentStore::query_sm(
870 const std::vector<C2Param*> &stackParams,
871 const std::vector<C2Param::Index> &heapParamIndices,
872 std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
873 return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
874 }
875
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)876 c2_status_t C2PlatformComponentStore::config_sm(
877 const std::vector<C2Param*> ¶ms,
878 std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
879 return mInterface.config(params, C2_MAY_BLOCK, failures);
880 }
881
listComponents()882 std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
883 // This method SHALL return within 500ms.
884 std::vector<std::shared_ptr<const C2Component::Traits>> list;
885 for (const C2String &alias : mComponentsList) {
886 ComponentLoader &loader = mComponents.at(alias);
887 std::shared_ptr<ComponentModule> module;
888 c2_status_t res = loader.fetchModule(&module);
889 if (res == C2_OK) {
890 std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
891 if (traits) {
892 list.push_back(traits);
893 }
894 }
895 }
896 return list;
897 }
898
findComponent(C2String name,ComponentLoader ** loader)899 c2_status_t C2PlatformComponentStore::findComponent(C2String name, ComponentLoader **loader) {
900 *loader = nullptr;
901 auto pos = mComponents.find(name);
902 // TODO: check aliases
903 if (pos == mComponents.end()) {
904 return C2_NOT_FOUND;
905 }
906 *loader = &pos->second;
907 return C2_OK;
908 }
909
createComponent(C2String name,std::shared_ptr<C2Component> * const component)910 c2_status_t C2PlatformComponentStore::createComponent(
911 C2String name, std::shared_ptr<C2Component> *const component) {
912 // This method SHALL return within 100ms.
913 component->reset();
914 ComponentLoader *loader;
915 c2_status_t res = findComponent(name, &loader);
916 if (res == C2_OK) {
917 std::shared_ptr<ComponentModule> module;
918 res = loader->fetchModule(&module);
919 if (res == C2_OK) {
920 // TODO: get a unique node ID
921 res = module->createComponent(0, component);
922 }
923 }
924 return res;
925 }
926
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)927 c2_status_t C2PlatformComponentStore::createInterface(
928 C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
929 // This method SHALL return within 100ms.
930 interface->reset();
931 ComponentLoader *loader;
932 c2_status_t res = findComponent(name, &loader);
933 if (res == C2_OK) {
934 std::shared_ptr<ComponentModule> module;
935 res = loader->fetchModule(&module);
936 if (res == C2_OK) {
937 // TODO: get a unique node ID
938 res = module->createInterface(0, interface);
939 }
940 }
941 return res;
942 }
943
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const944 c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
945 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
946 return mInterface.querySupportedParams(params);
947 }
948
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const949 c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
950 std::vector<C2FieldSupportedValuesQuery> &fields) const {
951 return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
952 }
953
getName() const954 C2String C2PlatformComponentStore::getName() const {
955 return "android.componentStore.platform";
956 }
957
getParamReflector() const958 std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
959 return mReflector;
960 }
961
GetCodec2PlatformComponentStore()962 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
963 static std::mutex mutex;
964 static std::weak_ptr<C2ComponentStore> platformStore;
965 std::lock_guard<std::mutex> lock(mutex);
966 std::shared_ptr<C2ComponentStore> store = platformStore.lock();
967 if (store == nullptr) {
968 store = std::make_shared<C2PlatformComponentStore>();
969 platformStore = store;
970 }
971 return store;
972 }
973
974 } // namespace android
975