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