1 /* Copyright (C) 2020 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 
13 #pragma once
14 
15 #include <map>
16 #include <mutex>
17 
18 #include <C2Component.h>
19 #include <C2ComponentFactory.h>
20 #include <android-base/thread_annotations.h>
21 #include <util/C2InterfaceHelper.h>
22 
23 namespace android {
24 
25 class GoldfishComponentStore : public C2ComponentStore {
26   public:
27     static std::shared_ptr<C2ComponentStore> Create();
28 
29     virtual std::vector<std::shared_ptr<const C2Component::Traits>>
30     listComponents() override;
31     virtual std::shared_ptr<C2ParamReflector>
32     getParamReflector() const override;
33     virtual C2String getName() const override;
34     virtual c2_status_t querySupportedValues_sm(
35         std::vector<C2FieldSupportedValuesQuery> &fields) const override;
36     virtual c2_status_t querySupportedParams_nb(
37         std::vector<std::shared_ptr<C2ParamDescriptor>> *const params)
38         const override;
39     virtual c2_status_t query_sm(
40         const std::vector<C2Param *> &stackParams,
41         const std::vector<C2Param::Index> &heapParamIndices,
42         std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
43     virtual c2_status_t createInterface(
44         C2String name,
45         std::shared_ptr<C2ComponentInterface> *const interface) override;
46     virtual c2_status_t
47     createComponent(C2String name,
48                     std::shared_ptr<C2Component> *const component) override;
49     virtual c2_status_t
50     copyBuffer(std::shared_ptr<C2GraphicBuffer> src,
51                std::shared_ptr<C2GraphicBuffer> dst) override;
52     virtual c2_status_t config_sm(
53         const std::vector<C2Param *> &params,
54         std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
55     GoldfishComponentStore();
56 
57     virtual ~GoldfishComponentStore() override = default;
58 
59   private:
60     /**
61      * An object encapsulating a loaded component module.
62      *
63      * \todo provide a way to add traits to known components here to avoid
64      * loading the .so-s for listComponents
65      */
66     struct ComponentModule
67         : public C2ComponentFactory,
68           public std::enable_shared_from_this<ComponentModule> {
69         virtual c2_status_t
70         createComponent(c2_node_id_t id,
71                         std::shared_ptr<C2Component> *component,
72                         ComponentDeleter deleter =
73                             std::default_delete<C2Component>()) override;
74         virtual c2_status_t createInterface(
75             c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
76             InterfaceDeleter deleter =
77                 std::default_delete<C2ComponentInterface>()) override;
78 
79         /**
80          * \returns the traits of the component in this module.
81          */
82         std::shared_ptr<const C2Component::Traits> getTraits();
83 
84         /**
85          * Creates an uninitialized component module.
86          *
87          * \param name[in]  component name.
88          *
89          * \note Only used by ComponentLoader.
90          */
ComponentModuleComponentModule91         ComponentModule()
92             : mInit(C2_NO_INIT), mLibHandle(nullptr), createFactory(nullptr),
93               destroyFactory(nullptr), mComponentFactory(nullptr) {}
94 
95         /**
96          * Initializes a component module with a given library path. Must be
97          * called exactly once.
98          *
99          * \note Only used by ComponentLoader.
100          *
101          * \param libPath[in] library path
102          *
103          * \retval C2_OK        the component module has been successfully
104          * loaded \retval C2_NO_MEMORY not enough memory to loading the
105          * component module \retval C2_NOT_FOUND could not locate the component
106          * module \retval C2_CORRUPTED the component module could not be loaded
107          * (unexpected) \retval C2_REFUSED   permission denied to load the
108          * component module (unexpected) \retval C2_TIMED_OUT could not load the
109          * module within the time limit (unexpected)
110          */
111         c2_status_t init(std::string libPath);
112 
113         virtual ~ComponentModule() override;
114 
115       protected:
116         std::recursive_mutex mLock; ///< lock protecting mTraits
117         std::shared_ptr<C2Component::Traits>
118             mTraits; ///< cached component traits
119 
120         c2_status_t mInit; ///< initialization result
121 
122         void *mLibHandle; ///< loaded library handle
123         C2ComponentFactory::CreateCodec2FactoryFunc
124             createFactory; ///< loaded create function
125         C2ComponentFactory::DestroyCodec2FactoryFunc
126             destroyFactory; ///< loaded destroy function
127         C2ComponentFactory
128             *mComponentFactory; ///< loaded/created component factory
129     };
130 
131     /**
132      * An object encapsulating a loadable component module.
133      *
134      * \todo make this also work for enumerations
135      */
136     struct ComponentLoader {
137         /**
138          * Load the component module.
139          *
140          * This method simply returns the component module if it is already
141          * currently loaded, or attempts to load it if it is not.
142          *
143          * \param module[out] pointer to the shared pointer where the loaded
144          * module shall be stored. This will be nullptr on error.
145          *
146          * \retval C2_OK        the component module has been successfully
147          * loaded \retval C2_NO_MEMORY not enough memory to loading the
148          * component module \retval C2_NOT_FOUND could not locate the component
149          * module \retval C2_CORRUPTED the component module could not be loaded
150          * \retval C2_REFUSED   permission denied to load the component module
151          */
fetchModuleComponentLoader152         c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
153             c2_status_t res = C2_OK;
154             std::lock_guard<std::mutex> lock(mMutex);
155             std::shared_ptr<ComponentModule> localModule = mModule.lock();
156             if (localModule == nullptr) {
157                 localModule = std::make_shared<ComponentModule>();
158                 res = localModule->init(mLibPath);
159                 if (res == C2_OK) {
160                     mModule = localModule;
161                 }
162             }
163             *module = localModule;
164             return res;
165         }
166 
167         /**
168          * Creates a component loader for a specific library path (or name).
169          */
ComponentLoaderComponentLoader170         ComponentLoader(std::string libPath) : mLibPath(libPath) {}
171 
172       private:
173         std::mutex mMutex; ///< mutex guarding the module
174         std::weak_ptr<ComponentModule>
175             mModule;          ///< weak reference to the loaded module
176         std::string mLibPath; ///< library path
177     };
178 
179     /**
180      * Retrieves the component module for a component.
181      *
182      * \param module pointer to a shared_pointer where the component module will
183      * be stored on success.
184      *
185      * \retval C2_OK        the component loader has been successfully retrieved
186      * \retval C2_NO_MEMORY not enough memory to locate the component loader
187      * \retval C2_NOT_FOUND could not locate the component to be loaded
188      * \retval C2_CORRUPTED the component loader could not be identified due to
189      * some modules being corrupted (this can happen if the name does not refer
190      * to an already identified component but some components could not be
191      * loaded due to bad library) \retval C2_REFUSED   permission denied to find
192      * the component loader for the named component (this can happen if the name
193      * does not refer to an already identified component but some components
194      * could not be loaded due to lack of permissions)
195      */
196     c2_status_t findComponent(C2String name,
197                               std::shared_ptr<ComponentModule> *module);
198 
199     /**
200      * Loads each component module and discover its contents.
201      */
202     void visitComponents();
203 
204     std::mutex
205         mMutex;    ///< mutex guarding the component lists during construction
206     bool mVisited; ///< component modules visited
207     std::map<C2String, ComponentLoader>
208         mComponents; ///< path -> component module
209     std::map<C2String, C2String> mComponentNameToPath; ///< name -> path
210     std::vector<std::shared_ptr<const C2Component::Traits>> mComponentList;
211 
212     std::shared_ptr<C2ReflectorHelper> mReflector;
213 };
214 } // namespace android
215