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*> &params,
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, &params);
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, &params);
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*> &params,
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