blob: f5dc838f5ee3264a7fd91ccc78c34921c7c42b17 [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
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>
Dongwon Kange55d13c2019-04-24 11:01:49 -070029#include <media/stagefright/foundation/ADebug.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080030#include <util/C2InterfaceHelper.h>
31
32#include <dlfcn.h>
33#include <unistd.h> // getpagesize
34
35#include <map>
36#include <memory>
37#include <mutex>
38
39namespace android {
40
41/**
42 * Returns the preferred component store in this process to access its interface.
43 */
44std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore();
45
46/**
47 * The platform allocator store provides basic allocator-types for the framework based on ion and
48 * gralloc. Allocators are not meant to be updatable.
49 *
50 * \todo Provide allocator based on ashmem
51 * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
52 * \todo Make this allocator store extendable
53 */
54class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
55public:
56 C2PlatformAllocatorStoreImpl();
57
58 virtual c2_status_t fetchAllocator(
59 id_t id, std::shared_ptr<C2Allocator> *const allocator) override;
60
61 virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb()
62 const override {
63 return std::vector<std::shared_ptr<const C2Allocator::Traits>>(); /// \todo
64 }
65
66 virtual C2String getName() const override {
67 return "android.allocator-store";
68 }
69
70 void setComponentStore(std::shared_ptr<C2ComponentStore> store);
71
72 ~C2PlatformAllocatorStoreImpl() override = default;
73
74private:
75 /// returns a shared-singleton ion allocator
76 std::shared_ptr<C2Allocator> fetchIonAllocator();
77
78 /// returns a shared-singleton gralloc allocator
79 std::shared_ptr<C2Allocator> fetchGrallocAllocator();
80
81 /// returns a shared-singleton bufferqueue supporting gralloc allocator
82 std::shared_ptr<C2Allocator> fetchBufferQueueAllocator();
83
84 /// component store to use
85 std::mutex _mComponentStoreSetLock; // protects the entire updating _mComponentStore and its
86 // dependencies
87 std::mutex _mComponentStoreReadLock; // must protect only read/write of _mComponentStore
88 std::shared_ptr<C2ComponentStore> _mComponentStore;
89};
90
91C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
92}
93
94c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
95 id_t id, std::shared_ptr<C2Allocator> *const allocator) {
96 allocator->reset();
97 switch (id) {
98 // TODO: should we implement a generic registry for all, and use that?
99 case C2PlatformAllocatorStore::ION:
100 case C2AllocatorStore::DEFAULT_LINEAR:
101 *allocator = fetchIonAllocator();
102 break;
103
104 case C2PlatformAllocatorStore::GRALLOC:
105 case C2AllocatorStore::DEFAULT_GRAPHIC:
106 *allocator = fetchGrallocAllocator();
107 break;
108
109 case C2PlatformAllocatorStore::BUFFERQUEUE:
110 *allocator = fetchBufferQueueAllocator();
111 break;
112
113 default:
114 // Try to create allocator from platform store plugins.
115 c2_status_t res =
116 C2PlatformStorePluginLoader::GetInstance()->createAllocator(id, allocator);
117 if (res != C2_OK) {
118 return res;
119 }
120 break;
121 }
122 if (*allocator == nullptr) {
123 return C2_NO_MEMORY;
124 }
125 return C2_OK;
126}
127
128namespace {
129
130std::mutex gIonAllocatorMutex;
131std::weak_ptr<C2AllocatorIon> gIonAllocator;
132
133void UseComponentStoreForIonAllocator(
134 const std::shared_ptr<C2AllocatorIon> allocator,
135 std::shared_ptr<C2ComponentStore> store) {
136 C2AllocatorIon::UsageMapperFn mapper;
137 uint64_t minUsage = 0;
138 uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected;
139 size_t blockSize = getpagesize();
140
141 // query min and max usage as well as block size via supported values
142 C2StoreIonUsageInfo usageInfo;
143 std::vector<C2FieldSupportedValuesQuery> query = {
144 C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.usage)),
145 C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.capacity)),
146 };
147 c2_status_t res = store->querySupportedValues_sm(query);
148 if (res == C2_OK) {
149 if (query[0].status == C2_OK) {
150 const C2FieldSupportedValues &fsv = query[0].values;
151 if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) {
152 minUsage = fsv.values[0].u64;
153 maxUsage = 0;
154 for (C2Value::Primitive v : fsv.values) {
155 maxUsage |= v.u64;
156 }
157 }
158 }
159 if (query[1].status == C2_OK) {
160 const C2FieldSupportedValues &fsv = query[1].values;
161 if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) {
162 blockSize = fsv.range.step.u32;
163 }
164 }
165
166 mapper = [store](C2MemoryUsage usage, size_t capacity,
167 size_t *align, unsigned *heapMask, unsigned *flags) -> c2_status_t {
168 if (capacity > UINT32_MAX) {
169 return C2_BAD_VALUE;
170 }
171 C2StoreIonUsageInfo usageInfo = { usage.expected, capacity };
172 std::vector<std::unique_ptr<C2SettingResult>> failures; // TODO: remove
173 c2_status_t res = store->config_sm({&usageInfo}, &failures);
174 if (res == C2_OK) {
175 *align = usageInfo.minAlignment;
176 *heapMask = usageInfo.heapMask;
177 *flags = usageInfo.allocFlags;
178 }
179 return res;
180 };
181 }
182
183 allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize);
184}
185
186}
187
188void C2PlatformAllocatorStoreImpl::setComponentStore(std::shared_ptr<C2ComponentStore> store) {
189 // technically this set lock is not needed, but is here for safety in case we add more
190 // getter orders
191 std::lock_guard<std::mutex> lock(_mComponentStoreSetLock);
192 {
193 std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
194 _mComponentStore = store;
195 }
196 std::shared_ptr<C2AllocatorIon> allocator;
197 {
198 std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
199 allocator = gIonAllocator.lock();
200 }
201 if (allocator) {
202 UseComponentStoreForIonAllocator(allocator, store);
203 }
204}
205
206std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
207 std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
208 std::shared_ptr<C2AllocatorIon> allocator = gIonAllocator.lock();
209 if (allocator == nullptr) {
210 std::shared_ptr<C2ComponentStore> componentStore;
211 {
212 std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
213 componentStore = _mComponentStore;
214 }
215 allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
216 UseComponentStoreForIonAllocator(allocator, componentStore);
217 gIonAllocator = allocator;
218 }
219 return allocator;
220}
221
222std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
223 static std::mutex mutex;
224 static std::weak_ptr<C2Allocator> grallocAllocator;
225 std::lock_guard<std::mutex> lock(mutex);
226 std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
227 if (allocator == nullptr) {
228 allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
229 grallocAllocator = allocator;
230 }
231 return allocator;
232}
233
234std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBufferQueueAllocator() {
235 static std::mutex mutex;
236 static std::weak_ptr<C2Allocator> grallocAllocator;
237 std::lock_guard<std::mutex> lock(mutex);
238 std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
239 if (allocator == nullptr) {
240 allocator = std::make_shared<C2AllocatorGralloc>(
241 C2PlatformAllocatorStore::BUFFERQUEUE, true);
242 grallocAllocator = allocator;
243 }
244 return allocator;
245}
246
247namespace {
248 std::mutex gPreferredComponentStoreMutex;
249 std::shared_ptr<C2ComponentStore> gPreferredComponentStore;
250
251 std::mutex gPlatformAllocatorStoreMutex;
252 std::weak_ptr<C2PlatformAllocatorStoreImpl> gPlatformAllocatorStore;
253}
254
255std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
256 std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
257 std::shared_ptr<C2PlatformAllocatorStoreImpl> store = gPlatformAllocatorStore.lock();
258 if (store == nullptr) {
259 store = std::make_shared<C2PlatformAllocatorStoreImpl>();
260 store->setComponentStore(GetPreferredCodec2ComponentStore());
261 gPlatformAllocatorStore = store;
262 }
263 return store;
264}
265
266void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore) {
267 static std::mutex mutex;
268 std::lock_guard<std::mutex> lock(mutex); // don't interleve set-s
269
270 // update preferred store
271 {
272 std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
273 gPreferredComponentStore = componentStore;
274 }
275
276 // update platform allocator's store as well if it is alive
277 std::shared_ptr<C2PlatformAllocatorStoreImpl> allocatorStore;
278 {
279 std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
280 allocatorStore = gPlatformAllocatorStore.lock();
281 }
282 if (allocatorStore) {
283 allocatorStore->setComponentStore(componentStore);
284 }
285}
286
287std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore() {
288 std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
289 return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore();
290}
291
292namespace {
293
294class _C2BlockPoolCache {
295public:
296 _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
297
298 c2_status_t _createBlockPool(
299 C2PlatformAllocatorStore::id_t allocatorId,
300 std::shared_ptr<const C2Component> component,
301 C2BlockPool::local_id_t poolId,
302 std::shared_ptr<C2BlockPool> *pool) {
303 std::shared_ptr<C2AllocatorStore> allocatorStore =
304 GetCodec2PlatformAllocatorStore();
305 std::shared_ptr<C2Allocator> allocator;
306 c2_status_t res = C2_NOT_FOUND;
307
308 switch(allocatorId) {
309 case C2PlatformAllocatorStore::ION:
310 case C2AllocatorStore::DEFAULT_LINEAR:
311 res = allocatorStore->fetchAllocator(
312 C2AllocatorStore::DEFAULT_LINEAR, &allocator);
313 if (res == C2_OK) {
314 std::shared_ptr<C2BlockPool> ptr =
315 std::make_shared<C2PooledBlockPool>(
316 allocator, poolId);
317 *pool = ptr;
318 mBlockPools[poolId] = ptr;
319 mComponents[poolId] = component;
320 }
321 break;
322 case C2PlatformAllocatorStore::GRALLOC:
323 case C2AllocatorStore::DEFAULT_GRAPHIC:
324 res = allocatorStore->fetchAllocator(
325 C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
326 if (res == C2_OK) {
327 std::shared_ptr<C2BlockPool> ptr =
328 std::make_shared<C2PooledBlockPool>(allocator, poolId);
329 *pool = ptr;
330 mBlockPools[poolId] = ptr;
331 mComponents[poolId] = component;
332 }
333 break;
334 case C2PlatformAllocatorStore::BUFFERQUEUE:
335 res = allocatorStore->fetchAllocator(
336 C2PlatformAllocatorStore::BUFFERQUEUE, &allocator);
337 if (res == C2_OK) {
338 std::shared_ptr<C2BlockPool> ptr =
339 std::make_shared<C2BufferQueueBlockPool>(
340 allocator, poolId);
341 *pool = ptr;
342 mBlockPools[poolId] = ptr;
343 mComponents[poolId] = component;
344 }
345 break;
346 default:
347 // Try to create block pool from platform store plugins.
348 std::shared_ptr<C2BlockPool> ptr;
349 res = C2PlatformStorePluginLoader::GetInstance()->createBlockPool(
350 allocatorId, poolId, &ptr);
351 if (res == C2_OK) {
352 *pool = ptr;
353 mBlockPools[poolId] = ptr;
354 mComponents[poolId] = component;
355 }
356 break;
357 }
358 return res;
359 }
360
361 c2_status_t createBlockPool(
362 C2PlatformAllocatorStore::id_t allocatorId,
363 std::shared_ptr<const C2Component> component,
364 std::shared_ptr<C2BlockPool> *pool) {
365 return _createBlockPool(allocatorId, component, mBlockPoolSeqId++, pool);
366 }
367
368 bool getBlockPool(
369 C2BlockPool::local_id_t blockPoolId,
370 std::shared_ptr<const C2Component> component,
371 std::shared_ptr<C2BlockPool> *pool) {
372 // TODO: use one iterator for multiple blockpool type scalability.
373 std::shared_ptr<C2BlockPool> ptr;
374 auto it = mBlockPools.find(blockPoolId);
375 if (it != mBlockPools.end()) {
376 ptr = it->second.lock();
377 if (!ptr) {
378 mBlockPools.erase(it);
379 mComponents.erase(blockPoolId);
380 } else {
381 auto found = mComponents.find(blockPoolId);
382 if (component == found->second.lock()) {
383 *pool = ptr;
384 return true;
385 }
386 }
387 }
388 return false;
389 }
390
391private:
392 C2BlockPool::local_id_t mBlockPoolSeqId;
393
394 std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
395 std::map<C2BlockPool::local_id_t, std::weak_ptr<const C2Component>> mComponents;
396};
397
398static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
399 std::make_unique<_C2BlockPoolCache>();
400static std::mutex sBlockPoolCacheMutex;
401
402} // anynymous namespace
403
404c2_status_t GetCodec2BlockPool(
405 C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
406 std::shared_ptr<C2BlockPool> *pool) {
407 pool->reset();
408 std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
409 std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
410 std::shared_ptr<C2Allocator> allocator;
411 c2_status_t res = C2_NOT_FOUND;
412
413 if (id >= C2BlockPool::PLATFORM_START) {
414 if (sBlockPoolCache->getBlockPool(id, component, pool)) {
415 return C2_OK;
416 }
417 }
418
419 switch (id) {
420 case C2BlockPool::BASIC_LINEAR:
421 res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
422 if (res == C2_OK) {
423 *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
424 }
425 break;
426 case C2BlockPool::BASIC_GRAPHIC:
427 res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
428 if (res == C2_OK) {
429 *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
430 }
431 break;
432 // TODO: remove this. this is temporary
433 case C2BlockPool::PLATFORM_START:
434 res = sBlockPoolCache->_createBlockPool(
435 C2PlatformAllocatorStore::BUFFERQUEUE, component, id, pool);
436 break;
437 default:
438 break;
439 }
440 return res;
441}
442
443c2_status_t CreateCodec2BlockPool(
444 C2PlatformAllocatorStore::id_t allocatorId,
445 std::shared_ptr<const C2Component> component,
446 std::shared_ptr<C2BlockPool> *pool) {
447 pool->reset();
448
449 std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
450 return sBlockPoolCache->createBlockPool(allocatorId, component, pool);
451}
452
453class C2PlatformComponentStore : public C2ComponentStore {
454public:
455 virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
456 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
457 virtual C2String getName() const override;
458 virtual c2_status_t querySupportedValues_sm(
459 std::vector<C2FieldSupportedValuesQuery> &fields) const override;
460 virtual c2_status_t querySupportedParams_nb(
461 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override;
462 virtual c2_status_t query_sm(
463 const std::vector<C2Param*> &stackParams,
464 const std::vector<C2Param::Index> &heapParamIndices,
465 std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
466 virtual c2_status_t createInterface(
467 C2String name, std::shared_ptr<C2ComponentInterface> *const interface) override;
468 virtual c2_status_t createComponent(
469 C2String name, std::shared_ptr<C2Component> *const component) override;
470 virtual c2_status_t copyBuffer(
471 std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) override;
472 virtual c2_status_t config_sm(
473 const std::vector<C2Param*> &params,
474 std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
475 C2PlatformComponentStore();
476
477 virtual ~C2PlatformComponentStore() override = default;
478
479private:
480
481 /**
482 * An object encapsulating a loaded component module.
483 *
484 * \todo provide a way to add traits to known components here to avoid loading the .so-s
485 * for listComponents
486 */
487 struct ComponentModule : public C2ComponentFactory,
488 public std::enable_shared_from_this<ComponentModule> {
489 virtual c2_status_t createComponent(
490 c2_node_id_t id, std::shared_ptr<C2Component> *component,
491 ComponentDeleter deleter = std::default_delete<C2Component>()) override;
492 virtual c2_status_t createInterface(
493 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
494 InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;
495
496 /**
497 * \returns the traits of the component in this module.
498 */
499 std::shared_ptr<const C2Component::Traits> getTraits();
500
501 /**
502 * Creates an uninitialized component module.
503 *
504 * \param name[in] component name.
505 *
506 * \note Only used by ComponentLoader.
507 */
508 ComponentModule()
509 : mInit(C2_NO_INIT),
510 mLibHandle(nullptr),
511 createFactory(nullptr),
512 destroyFactory(nullptr),
513 mComponentFactory(nullptr) {
514 }
515
516 /**
517 * Initializes a component module with a given library path. Must be called exactly once.
518 *
519 * \note Only used by ComponentLoader.
520 *
Pawin Vongmasa36653902018-11-15 00:10:25 -0800521 * \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 */
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800530 c2_status_t init(std::string libPath);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800531
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 */
567 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>();
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800573 res = localModule->init(mLibPath);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800574 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 */
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800585 ComponentLoader(std::string libPath)
586 : mLibPath(libPath) {}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800587
588 private:
589 std::mutex mMutex; ///< mutex guarding the module
590 std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
Pawin Vongmasa36653902018-11-15 00:10:25 -0800591 std::string mLibPath; ///< library path
592 };
593
594 struct Interface : public C2InterfaceHelper {
595 std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
596
597 Interface(std::shared_ptr<C2ReflectorHelper> reflector)
598 : C2InterfaceHelper(reflector) {
599 setDerivedInstance(this);
600
601 struct Setter {
602 static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
603 me.set().heapMask = ~0;
604 me.set().allocFlags = 0;
605 me.set().minAlignment = 0;
606 return C2R::Ok();
607 }
608 };
609
610 addParameter(
611 DefineParam(mIonUsageInfo, "ion-usage")
612 .withDefault(new C2StoreIonUsageInfo())
613 .withFields({
614 C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
615 C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
616 C2F(mIonUsageInfo, heapMask).any(),
617 C2F(mIonUsageInfo, allocFlags).flags({}),
618 C2F(mIonUsageInfo, minAlignment).equalTo(0)
619 })
620 .withSetter(Setter::setIonUsage)
621 .build());
622 }
623 };
624
625 /**
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800626 * Retrieves the component module for a component.
Pawin Vongmasa36653902018-11-15 00:10:25 -0800627 *
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800628 * \param module pointer to a shared_pointer where the component module will be stored on
629 * success.
Pawin Vongmasa36653902018-11-15 00:10:25 -0800630 *
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 */
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800643 c2_status_t findComponent(C2String name, std::shared_ptr<ComponentModule> *module);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800644
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800645 /**
646 * Loads each component module and discover its contents.
647 */
648 void visitComponents();
649
650 std::mutex mMutex; ///< mutex guarding the component lists during construction
651 bool mVisited; ///< component modules visited
652 std::map<C2String, ComponentLoader> mComponents; ///< path -> component module
653 std::map<C2String, C2String> mComponentNameToPath; ///< name -> path
654 std::vector<std::shared_ptr<const C2Component::Traits>> mComponentList;
655
Pawin Vongmasa36653902018-11-15 00:10:25 -0800656 std::shared_ptr<C2ReflectorHelper> mReflector;
657 Interface mInterface;
658};
659
660c2_status_t C2PlatformComponentStore::ComponentModule::init(
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800661 std::string libPath) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800662 ALOGV("in %s", __func__);
663 ALOGV("loading dll");
664 mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
Dongwon Kange55d13c2019-04-24 11:01:49 -0700665 if (mLibHandle == nullptr) {
666 LOG_ALWAYS_FATAL_IN_CHILD_PROC("could not dlopen %s: %s", libPath.c_str(), dlerror());
667 mInit = C2_CORRUPTED;
668 return mInit;
669 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800670
Chong Zhangf5c7ca82019-04-23 17:06:21 -0700671 createFactory =
672 (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
Dongwon Kange55d13c2019-04-24 11:01:49 -0700673 if (createFactory == nullptr) {
674 LOG_ALWAYS_FATAL_IN_CHILD_PROC("createFactory is null in %s", libPath.c_str());
675 mInit = C2_CORRUPTED;
676 return mInit;
677 }
Chong Zhangf5c7ca82019-04-23 17:06:21 -0700678
679 destroyFactory =
680 (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
Dongwon Kange55d13c2019-04-24 11:01:49 -0700681 if (destroyFactory == nullptr) {
682 LOG_ALWAYS_FATAL_IN_CHILD_PROC("destroyFactory is null in %s", libPath.c_str());
683 mInit = C2_CORRUPTED;
684 return mInit;
685 }
Chong Zhangf5c7ca82019-04-23 17:06:21 -0700686
687 mComponentFactory = createFactory();
688 if (mComponentFactory == nullptr) {
689 ALOGD("could not create factory in %s", libPath.c_str());
690 mInit = C2_NO_MEMORY;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800691 return mInit;
692 }
693
Dongwon Kange55d13c2019-04-24 11:01:49 -0700694 mInit = C2_OK;
695
Pawin Vongmasa36653902018-11-15 00:10:25 -0800696 std::shared_ptr<C2ComponentInterface> intf;
697 c2_status_t res = createInterface(0, &intf);
698 if (res != C2_OK) {
699 ALOGD("failed to create interface: %d", res);
700 return mInit;
701 }
702
703 std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
704 if (traits) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800705 traits->name = intf->getName();
Lajos Molnar62d62d62019-01-31 16:26:46 -0800706
707 C2ComponentKindSetting kind;
708 C2ComponentDomainSetting domain;
709 res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
710 bool fixDomain = res != C2_OK;
711 if (res == C2_OK) {
712 traits->kind = kind.value;
713 traits->domain = domain.value;
714 } else {
715 // TODO: remove this fall-back
716 ALOGD("failed to query interface for kind and domain: %d", res);
717
718 traits->kind =
719 (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
720 (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
721 C2Component::KIND_OTHER;
722 }
723
724 uint32_t mediaTypeIndex =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800725 traits->kind == C2Component::KIND_ENCODER ? C2PortMediaTypeSetting::output::PARAM_TYPE
726 : C2PortMediaTypeSetting::input::PARAM_TYPE;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800727 std::vector<std::unique_ptr<C2Param>> params;
728 res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
729 if (res != C2_OK) {
730 ALOGD("failed to query interface: %d", res);
731 return mInit;
732 }
733 if (params.size() != 1u) {
734 ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
735 return mInit;
736 }
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800737 C2PortMediaTypeSetting *mediaTypeConfig = C2PortMediaTypeSetting::From(params[0].get());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800738 if (mediaTypeConfig == nullptr) {
739 ALOGD("failed to query media type");
740 return mInit;
741 }
Lajos Molnar62d62d62019-01-31 16:26:46 -0800742 traits->mediaType =
743 std::string(mediaTypeConfig->m.value,
744 strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800745
Lajos Molnar62d62d62019-01-31 16:26:46 -0800746 if (fixDomain) {
747 if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
748 traits->domain = C2Component::DOMAIN_AUDIO;
749 } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
750 traits->domain = C2Component::DOMAIN_VIDEO;
751 } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
752 traits->domain = C2Component::DOMAIN_IMAGE;
753 } else {
754 traits->domain = C2Component::DOMAIN_OTHER;
755 }
756 }
757
758 // TODO: get this properly from the store during emplace
759 switch (traits->domain) {
760 case C2Component::DOMAIN_AUDIO:
761 traits->rank = 8;
762 break;
763 default:
764 traits->rank = 512;
765 }
766
767 params.clear();
768 res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, &params);
769 if (res == C2_OK && params.size() == 1u) {
770 C2ComponentAliasesSetting *aliasesSetting =
771 C2ComponentAliasesSetting::From(params[0].get());
772 if (aliasesSetting) {
773 // Split aliases on ','
774 // This looks simpler in plain C and even std::string would still make a copy.
775 char *aliases = ::strndup(aliasesSetting->m.value, aliasesSetting->flexCount());
776 ALOGD("'%s' has aliases: '%s'", intf->getName().c_str(), aliases);
777
778 for (char *tok, *ptr, *str = aliases; (tok = ::strtok_r(str, ",", &ptr));
779 str = nullptr) {
780 traits->aliases.push_back(tok);
781 ALOGD("adding alias: '%s'", tok);
782 }
783 free(aliases);
784 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800785 }
786 }
787 mTraits = traits;
788
789 return mInit;
790}
791
792C2PlatformComponentStore::ComponentModule::~ComponentModule() {
793 ALOGV("in %s", __func__);
794 if (destroyFactory && mComponentFactory) {
795 destroyFactory(mComponentFactory);
796 }
797 if (mLibHandle) {
798 ALOGV("unloading dll");
799 dlclose(mLibHandle);
800 }
801}
802
803c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
804 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
805 std::function<void(::C2ComponentInterface*)> deleter) {
806 interface->reset();
807 if (mInit != C2_OK) {
808 return mInit;
809 }
810 std::shared_ptr<ComponentModule> module = shared_from_this();
811 c2_status_t res = mComponentFactory->createInterface(
812 id, interface, [module, deleter](C2ComponentInterface *p) mutable {
813 // capture module so that we ensure we still have it while deleting interface
814 deleter(p); // delete interface first
815 module.reset(); // remove module ref (not technically needed)
816 });
817 return res;
818}
819
820c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
821 c2_node_id_t id, std::shared_ptr<C2Component> *component,
822 std::function<void(::C2Component*)> deleter) {
823 component->reset();
824 if (mInit != C2_OK) {
825 return mInit;
826 }
827 std::shared_ptr<ComponentModule> module = shared_from_this();
828 c2_status_t res = mComponentFactory->createComponent(
829 id, component, [module, deleter](C2Component *p) mutable {
830 // capture module so that we ensure we still have it while deleting component
831 deleter(p); // delete component first
832 module.reset(); // remove module ref (not technically needed)
833 });
834 return res;
835}
836
837std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
838 std::unique_lock<std::recursive_mutex> lock(mLock);
839 return mTraits;
840}
841
842C2PlatformComponentStore::C2PlatformComponentStore()
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800843 : mVisited(false),
844 mReflector(std::make_shared<C2ReflectorHelper>()),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800845 mInterface(mReflector) {
846
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800847 auto emplace = [this](const char *libPath) {
848 mComponents.emplace(libPath, libPath);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800849 };
Pawin Vongmasa36653902018-11-15 00:10:25 -0800850
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800851 // TODO: move this also into a .so so it can be updated
852 emplace("libcodec2_soft_aacdec.so");
853 emplace("libcodec2_soft_aacenc.so");
854 emplace("libcodec2_soft_amrnbdec.so");
855 emplace("libcodec2_soft_amrnbenc.so");
856 emplace("libcodec2_soft_amrwbdec.so");
857 emplace("libcodec2_soft_amrwbenc.so");
858 emplace("libcodec2_soft_av1dec.so");
859 emplace("libcodec2_soft_avcdec.so");
860 emplace("libcodec2_soft_avcenc.so");
861 emplace("libcodec2_soft_flacdec.so");
862 emplace("libcodec2_soft_flacenc.so");
863 emplace("libcodec2_soft_g711alawdec.so");
864 emplace("libcodec2_soft_g711mlawdec.so");
865 emplace("libcodec2_soft_gsmdec.so");
866 emplace("libcodec2_soft_h263dec.so");
867 emplace("libcodec2_soft_h263enc.so");
868 emplace("libcodec2_soft_hevcdec.so");
Roma Kauldfe650a2018-08-02 17:48:51 +0530869 emplace("libcodec2_soft_hevcenc.so");
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800870 emplace("libcodec2_soft_mp3dec.so");
871 emplace("libcodec2_soft_mpeg2dec.so");
872 emplace("libcodec2_soft_mpeg4dec.so");
873 emplace("libcodec2_soft_mpeg4enc.so");
874 emplace("libcodec2_soft_opusdec.so");
875 emplace("libcodec2_soft_opusenc.so");
876 emplace("libcodec2_soft_rawdec.so");
877 emplace("libcodec2_soft_vorbisdec.so");
878 emplace("libcodec2_soft_vp8dec.so");
879 emplace("libcodec2_soft_vp8enc.so");
880 emplace("libcodec2_soft_vp9dec.so");
881 emplace("libcodec2_soft_vp9enc.so");
882 emplace("libcodec2_soft_xaacdec.so");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800883}
884
885c2_status_t C2PlatformComponentStore::copyBuffer(
886 std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
887 (void)src;
888 (void)dst;
889 return C2_OMITTED;
890}
891
892c2_status_t C2PlatformComponentStore::query_sm(
893 const std::vector<C2Param*> &stackParams,
894 const std::vector<C2Param::Index> &heapParamIndices,
895 std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
896 return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
897}
898
899c2_status_t C2PlatformComponentStore::config_sm(
900 const std::vector<C2Param*> &params,
901 std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
902 return mInterface.config(params, C2_MAY_BLOCK, failures);
903}
904
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800905void C2PlatformComponentStore::visitComponents() {
906 std::lock_guard<std::mutex> lock(mMutex);
907 if (mVisited) {
908 return;
909 }
910 for (auto &pathAndLoader : mComponents) {
911 const C2String &path = pathAndLoader.first;
912 ComponentLoader &loader = pathAndLoader.second;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800913 std::shared_ptr<ComponentModule> module;
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800914 if (loader.fetchModule(&module) == C2_OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800915 std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
916 if (traits) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800917 mComponentList.push_back(traits);
918 mComponentNameToPath.emplace(traits->name, path);
919 for (const C2String &alias : traits->aliases) {
920 mComponentNameToPath.emplace(alias, path);
921 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800922 }
923 }
924 }
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800925 mVisited = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800926}
927
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800928std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
929 // This method SHALL return within 500ms.
930 visitComponents();
931 return mComponentList;
932}
933
934c2_status_t C2PlatformComponentStore::findComponent(
935 C2String name, std::shared_ptr<ComponentModule> *module) {
936 (*module).reset();
937 visitComponents();
938
939 auto pos = mComponentNameToPath.find(name);
940 if (pos != mComponentNameToPath.end()) {
941 return mComponents.at(pos->second).fetchModule(module);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800942 }
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800943 return C2_NOT_FOUND;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800944}
945
946c2_status_t C2PlatformComponentStore::createComponent(
947 C2String name, std::shared_ptr<C2Component> *const component) {
948 // This method SHALL return within 100ms.
949 component->reset();
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800950 std::shared_ptr<ComponentModule> module;
951 c2_status_t res = findComponent(name, &module);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800952 if (res == C2_OK) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800953 // TODO: get a unique node ID
954 res = module->createComponent(0, component);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800955 }
956 return res;
957}
958
959c2_status_t C2PlatformComponentStore::createInterface(
960 C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
961 // This method SHALL return within 100ms.
962 interface->reset();
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800963 std::shared_ptr<ComponentModule> module;
964 c2_status_t res = findComponent(name, &module);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800965 if (res == C2_OK) {
Lajos Molnarc9b4ca02019-01-31 16:24:45 -0800966 // TODO: get a unique node ID
967 res = module->createInterface(0, interface);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800968 }
969 return res;
970}
971
972c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
973 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
974 return mInterface.querySupportedParams(params);
975}
976
977c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
978 std::vector<C2FieldSupportedValuesQuery> &fields) const {
979 return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
980}
981
982C2String C2PlatformComponentStore::getName() const {
983 return "android.componentStore.platform";
984}
985
986std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
987 return mReflector;
988}
989
990std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
991 static std::mutex mutex;
992 static std::weak_ptr<C2ComponentStore> platformStore;
993 std::lock_guard<std::mutex> lock(mutex);
994 std::shared_ptr<C2ComponentStore> store = platformStore.lock();
995 if (store == nullptr) {
996 store = std::make_shared<C2PlatformComponentStore>();
997 platformStore = store;
998 }
999 return store;
1000}
1001
1002} // namespace android