1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "plugin_registry.h"
17 
18 #include <algorithm>
19 
20 #include <base/util/uid_util.h>
21 #include <core/ecs/intf_component_manager.h>
22 #include <core/log.h>
23 
24 #include "image/loaders/image_loader_ktx.h"
25 #include "image/loaders/image_loader_stb_image.h"
26 #include "image/loaders/image_loader_libpng.h"
27 #include "image/loaders/image_loader_libjpeg.h"
28 #include "io/file_manager.h"
29 #include "io/std_filesystem.h"
30 #include "os/intf_library.h"
31 #include "static_plugin_decl.h"
32 
33 CORE_BEGIN_NAMESPACE()
34 using BASE_NS::array_view;
35 using BASE_NS::move;
36 using BASE_NS::pair;
37 using BASE_NS::reverse_iterator;
38 using BASE_NS::string;
39 using BASE_NS::string_view;
40 using BASE_NS::to_string;
41 using BASE_NS::Uid;
42 using BASE_NS::vector;
43 
44 IInterface* CreateFileMonitor(CORE_NS::IClassFactory& registry, CORE_NS::PluginToken token);
45 IInterface* GetFileApiFactory(CORE_NS::IClassRegister& registry, CORE_NS::PluginToken token);
46 
47 namespace StaticPluginRegistry {
48 // static_plugin_registry magic begin
49 #if defined(CORE_USE_COMPILER_GENERATED_STATIC_LIST) && (CORE_USE_COMPILER_GENERATED_STATIC_LIST == 1)
50 
51 #if _MSC_VER
52 #pragma section("spd$b", long, read)
53 #pragma section("spd$d", long, read)
54 #pragma section("spd$e", long, read)
55 __declspec(allocate("spd$b")) static constexpr const IPlugin* g_staticPluginList = nullptr;
56 __declspec(allocate("spd$e")) static constexpr const IPlugin* g_staticPluginListEnd = nullptr;
57 #else
58 // clang-format off
59 __asm__(
60     ".pushsection " SECTION(spl.1)
61     " .local g_staticPluginList\n"
62     " g_staticPluginList:\n"
63     ".dc.a 0x0\n"
64     ".section " SECTION(spl.2)
65     " .local g_staticPluginListData\n"
66     "g_staticPluginListData:\n"
67     " .dc.a 0x0\n"
68     " .section " SECTION(spl.3)
69     " .local g_staticPluginListEnd\n"
70     " g_staticPluginListEnd:\n"
71     ".dc.a 0x0\n"
72     " .popsection\n");
73 // clang-format on
74 extern "C" {
75 extern CORE_NS::IPlugin const* const g_staticPluginList;
76 extern CORE_NS::IPlugin const* const g_staticPluginListData;
77 extern CORE_NS::IPlugin const* const g_staticPluginListEnd;
78 __attribute__((used)) CORE_NS::IPlugin const* const g_staticPluginListDataRef = g_staticPluginListData;
79 }
80 #endif
81 
82 #else
83 
84 #if _MSC_VER
85 static CORE_NS::IPlugin const* const* g_staticPluginList = nullptr;
86 static size_t g_staticPluginListCount = 0;
87 #else
88 __attribute__((visibility("hidden"))) static CORE_NS::IPlugin const* const* g_staticPluginList = nullptr;
89 __attribute__((visibility("hidden"))) static size_t g_staticPluginListCount = 0;
90 #endif
91 
92 void RegisterStaticPlugin(const CORE_NS::IPlugin& plugin)
93 {
94     static BASE_NS::vector<const CORE_NS::IPlugin*> gGlobalPlugins;
95     gGlobalPlugins.push_back(&plugin);
96     g_staticPluginList = gGlobalPlugins.data();
97     g_staticPluginListCount = gGlobalPlugins.size();
98 }
99 #endif
100 } // namespace StaticPluginRegistry
101 
102 namespace {
103 struct LibPlugin {
104     ILibrary::Ptr lib;
105     const IPlugin* plugin;
106 };
107 
108 template<typename Container, typename Predicate>
FindIf(const Container & container,Predicate && predicate)109 inline typename Container::const_iterator FindIf(const Container& container, Predicate&& predicate)
110 {
111     return std::find_if(container.cbegin(), container.cend(), BASE_NS::forward<Predicate>(predicate));
112 }
113 
114 template<typename Container, typename Predicate>
NoneOf(const Container & container,Predicate && predicate)115 inline bool NoneOf(const Container& container, Predicate&& predicate)
116 {
117     return std::none_of(container.cbegin(), container.cend(), BASE_NS::forward<Predicate>(predicate));
118 }
119 
120 template<typename Container, typename Predicate>
AllOf(const Container & container,Predicate && predicate)121 inline bool AllOf(const Container& container, Predicate&& predicate)
122 {
123     return std::all_of(container.cbegin(), container.cend(), BASE_NS::forward<Predicate>(predicate));
124 }
125 
GatherStaticPlugins(vector<LibPlugin> & plugins)126 void GatherStaticPlugins(vector<LibPlugin>& plugins)
127 {
128     CORE_LOG_V("Static plugins:");
129 #if defined(CORE_USE_COMPILER_GENERATED_STATIC_LIST) && (CORE_USE_COMPILER_GENERATED_STATIC_LIST == 1)
130     const array_view<const IPlugin* const> staticPluginRegistry(
131         &StaticPluginRegistry::g_staticPluginList, &StaticPluginRegistry::g_staticPluginListEnd);
132 #else
133     const array_view<const IPlugin* const> staticPluginRegistry(
134         StaticPluginRegistry::g_staticPluginList, StaticPluginRegistry::g_staticPluginListCount);
135 #endif
136 
137     for (const auto plugin : staticPluginRegistry) {
138         if (plugin && (plugin->typeUid == IPlugin::UID)) {
139             CORE_LOG_V("\t%s", plugin->name);
140             plugins.push_back({ nullptr, plugin });
141         }
142     }
143 }
144 
GatherDynamicPlugins(vector<LibPlugin> & plugins,IFileManager & fileManager)145 void GatherDynamicPlugins(vector<LibPlugin>& plugins, IFileManager& fileManager)
146 {
147     CORE_LOG_V("Dynamic plugins:");
148     const auto libraryFileExtension = ILibrary::GetFileExtension();
149     constexpr string_view pluginRoot { "plugins://" };
150     if (IDirectory::Ptr pluginFiles = fileManager.OpenDirectory(pluginRoot); pluginFiles) {
151         for (const auto& file : pluginFiles->GetEntries()) {
152             const string_view pluginFile = file.name;
153             if (pluginFile.ends_with(libraryFileExtension)) {
154                 const string absoluteFile = fileManager.GetEntry(pluginRoot + file.name).name;
155                 if (ILibrary::Ptr lib = ILibrary::Load(absoluteFile); lib) {
156                     const IPlugin* plugin = lib->GetPlugin();
157                     if (plugin && (plugin->typeUid == IPlugin::UID)) {
158                         CORE_LOG_V("\t%s", plugin->name);
159                         plugins.push_back({ move(lib), plugin });
160                     }
161                 }
162             }
163         }
164     }
165 }
166 
Notify(const array_view<IPluginRegister::ITypeInfoListener * > listeners,IPluginRegister::ITypeInfoListener::EventType type,array_view<const ITypeInfo * const> typeInfos)167 void Notify(const array_view<IPluginRegister::ITypeInfoListener*> listeners,
168     IPluginRegister::ITypeInfoListener::EventType type, array_view<const ITypeInfo* const> typeInfos)
169 {
170     for (IPluginRegister::ITypeInfoListener* listener : listeners) {
171         if (listener) {
172             listener->OnTypeInfoEvent(type, typeInfos);
173         }
174     }
175 }
176 static constexpr CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo KTX_LOADER {
177     { CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo::UID },
178     nullptr,
179     BASE_NS::Uid { "306357a4-d49c-4670-9746-5ccbba567dc9" },
180     CreateImageLoaderKtx,
181     KTX_IMAGE_TYPES,
182 };
183 static constexpr CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo STB_LOADER {
184     { CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo::UID },
185     nullptr,
186     BASE_NS::Uid { "a5049cb8-10bb-4047-b7f5-e9939d5bb3a5" },
187     CreateImageLoaderStbImage,
188     STB_IMAGE_TYPES,
189 };
190 static constexpr CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo PNG_LOADER {
191     { CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo::UID },
192     nullptr,
193     BASE_NS::Uid { "dacbcb8d-60d6-4337-8295-7af99b517c1d" },
194     CreateImageLoaderLibPNGImage,
195     PNG_IMAGE_TYPES,
196 };
197 static constexpr CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo JPEG_LOADER {
198     { CORE_NS::IImageLoaderManager::ImageLoaderTypeInfo::UID },
199     nullptr,
200     BASE_NS::Uid { "c5fb2284-561f-4078-8a00-74b82f161964" },
201     CreateImageLoaderLibJPEGImage,
202     JPEG_IMAGE_TYPES,
203 };
204 } // namespace
205 
RegisterGlobalInterfaces(PluginRegistry & registry)206 vector<InterfaceTypeInfo> PluginRegistry::RegisterGlobalInterfaces(PluginRegistry& registry)
207 {
208     vector<InterfaceTypeInfo> interfaces = {
209         InterfaceTypeInfo { &registry, UID_LOGGER, GetName<ILogger>().data(), nullptr,
210             [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
211                 return &static_cast<PluginRegistry*>(token)->logger_;
212             } },
213         InterfaceTypeInfo { &registry, UID_FRUSTUM_UTIL, GetName<IFrustumUtil>().data(), nullptr,
214             [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
215                 return &static_cast<PluginRegistry*>(token)->frustumUtil_;
216             } },
217         InterfaceTypeInfo { &registry, UID_ENGINE_FACTORY, GetName<IEngineFactory>().data(), nullptr,
218             [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
219                 return static_cast<PluginRegistry*>(token)->engineFactory_.GetInterface(IEngineFactory::UID);
220             } },
221         InterfaceTypeInfo { &registry, UID_SYSTEM_GRAPH_LOADER, GetName<ISystemGraphLoaderFactory>().data(), nullptr,
222             [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
223                 return &static_cast<PluginRegistry*>(token)->systemGraphLoadeFactory;
224             } },
225         InterfaceTypeInfo { &registry, UID_GLOBAL_FACTORY, "Global registry factory", nullptr,
226             [](IClassRegister& registry, PluginToken /* token */) -> IInterface* {
227                 return registry.GetInterface<IClassFactory>();
228             } },
229         InterfaceTypeInfo {
230             &registry, UID_FILESYSTEM_API_FACTORY, "Filesystem API factory", nullptr, GetFileApiFactory },
231         InterfaceTypeInfo { &registry, UID_FILE_MONITOR, "Filemonitor", CreateFileMonitor, nullptr },
232         InterfaceTypeInfo { &registry, UID_FILE_MANAGER, "FileManager",
233             [](IClassFactory& /* factory */, PluginToken /* token */) -> IInterface* {
234                 return new CORE_NS::FileManager();
235             },
236             nullptr },
237         InterfaceTypeInfo { &registry, UID_TASK_QUEUE_FACTORY, "Task queue factory", nullptr,
238             [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
239                 return &static_cast<PluginRegistry*>(token)->taskQueueFactory_;
240             } },
241 #if (CORE_PERF_ENABLED == 1)
242         InterfaceTypeInfo { &registry, UID_PERFORMANCE_FACTORY, GetName<IPerformanceDataManagerFactory>().data(),
243             nullptr,
244             [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
245                 return &static_cast<PluginRegistry*>(token)->perfManFactory_;
246             } }
247 #endif
248     };
249 
250     for (const auto& info : interfaces) {
251         registry.RegisterInterfaceType(info);
252     }
253     registry.RegisterTypeInfo(KTX_LOADER);
254     registry.RegisterTypeInfo(STB_LOADER);
255     registry.RegisterTypeInfo(PNG_LOADER);
256     registry.RegisterTypeInfo(JPEG_LOADER);
257     return interfaces;
258 }
259 
UnregisterGlobalInterfaces()260 void PluginRegistry::UnregisterGlobalInterfaces()
261 {
262     UnregisterTypeInfo(STB_LOADER);
263     UnregisterTypeInfo(KTX_LOADER);
264     UnregisterTypeInfo(PNG_LOADER);
265     UnregisterTypeInfo(JPEG_LOADER);
266     for (const auto& info : ownInterfaceInfos_) {
267         UnregisterInterfaceType(info);
268     }
269 }
270 
PluginRegistry()271 PluginRegistry::PluginRegistry()
272 {
273     ownInterfaceInfos_ = RegisterGlobalInterfaces(*this);
274 }
275 
~PluginRegistry()276 PluginRegistry::~PluginRegistry()
277 {
278     UnloadPlugins({});
279     UnregisterGlobalInterfaces();
280 }
281 
282 // IPluginRegister
GetPlugins() const283 array_view<const IPlugin* const> PluginRegistry::GetPlugins() const
284 {
285     return plugins_;
286 }
287 
LoadPlugins(const array_view<const Uid> pluginUids)288 bool PluginRegistry::LoadPlugins(const array_view<const Uid> pluginUids)
289 {
290     // Gather all the available static and dynamic libraries.
291     vector<LibPlugin> plugins;
292     GatherStaticPlugins(plugins);
293     GatherDynamicPlugins(plugins, fileManager_);
294 
295     // If a list of UIDs was given remove all except the requires plugins.
296     if (!pluginUids.empty()) {
297         // Gather dependencies of each plugin.
298         vector<Uid> toLoad;
299         toLoad.reserve(plugins.size());
300 
301         auto addDependencies = [](auto&& addDependencies, vector<Uid>& toBeLoaded,
302                                    const vector<LibPlugin>& availablePlugins,
303                                    BASE_NS::vector<const IPlugin*>& loadedPlugins, const Uid& uidToLoad) -> bool {
304             bool found = true;
305             // Only consider plugins which are not already loaded, and not yet in the loading list.
306             if (NoneOf(
307                     loadedPlugins, [&uidToLoad](const IPlugin* loaded) { return loaded->version.uid == uidToLoad; }) &&
308                 NoneOf(toBeLoaded, [&uidToLoad](const Uid& willLoad) { return willLoad == uidToLoad; })) {
309                 if (auto pos = FindIf(availablePlugins,
310                         [&uidToLoad](
311                             const LibPlugin& libPlugin) { return libPlugin.plugin->version.uid == uidToLoad; });
312                     pos != availablePlugins.end()) {
313                     found = AllOf(pos->plugin->pluginDependencies, [&](const Uid& dependency) {
314                         return addDependencies(
315                             addDependencies, toBeLoaded, availablePlugins, loadedPlugins, dependency);
316                     });
317                     if (found) {
318                         toBeLoaded.push_back(uidToLoad);
319                     } else {
320                         CORE_LOG_E("Missing dependencies for: %s", to_string(uidToLoad).data());
321                     }
322                 } else {
323                     CORE_LOG_E("Plugin not found: %s", to_string(uidToLoad).data());
324                     found = false;
325                 }
326             }
327             return found;
328         };
329         const bool found = AllOf(pluginUids,
330             [&](const Uid& uid) { return addDependencies(addDependencies, toLoad, plugins, plugins_, uid); });
331 
332         // Order the available plugins to match the to-be-loaded list and remove extras.
333         auto begin = plugins.begin();
334         auto end = plugins.end();
335         for (const Uid& uid : toLoad) {
336             if (auto pos = std::find_if(
337                     begin, end, [uid](const LibPlugin& libPlugin) { return libPlugin.plugin->version.uid == uid; });
338                 pos != end) {
339                 std::rotate(begin, pos, end);
340                 ++begin;
341             }
342         }
343         plugins.erase(begin, end);
344 
345         if (!found) {
346             CORE_LOG_E("Unable to load plugins:");
347             for (const auto& uid : pluginUids) {
348                 if (NoneOf(plugins, [uid](const auto& available) { return available.plugin->version.uid == uid; })) {
349                     CORE_LOG_E("\t%s", to_string(uid).data());
350                 }
351             }
352             return false;
353         }
354     }
355 
356     // Now we should have only the desired plugins and can load all of them.
357     CORE_LOG_D("Load plugins:");
358     loading_ = true;
359     for (auto& plugin : plugins) {
360         RegisterPlugin(move(plugin.lib), *plugin.plugin,
361             NoneOf(pluginUids,
362                 [&loading = (plugin.plugin->version.uid)](const Uid& userRequest) { return userRequest == loading; }));
363     }
364     loading_ = false;
365 
366     if (!newTypeInfos_.empty()) {
367         Notify(typeInfoListeners_, ITypeInfoListener::EventType::ADDED, newTypeInfos_);
368         newTypeInfos_.clear();
369     }
370 
371     return true;
372 }
373 
UnloadPlugins(const array_view<const Uid> pluginUids)374 void PluginRegistry::UnloadPlugins(const array_view<const Uid> pluginUids)
375 {
376     CORE_LOG_D("Unload plugins:");
377     if (pluginUids.empty()) {
378         while (!pluginDatas_.empty() && !plugins_.empty()) {
379             UnregisterPlugin(*plugins_.back(), pluginDatas_.back().token);
380             plugins_.pop_back();
381             pluginDatas_.pop_back();
382         }
383         plugins_.clear();
384         pluginDatas_.clear();
385     } else {
386         [](array_view<const IPlugin*> plugins, array_view<PluginData> pluginDatas,
387             const array_view<const Uid>& pluginUids) {
388             auto recurse = [](const array_view<const IPlugin*>& plugins, array_view<PluginData>& pluginDatas,
389                                const array_view<const Uid>& pluginUids, auto& recurseRef) -> void {
390                 for (const auto& uid : pluginUids) {
391                     if (auto pos = std::find_if(plugins.begin(), plugins.end(),
392                             [uid](const IPlugin* pl) { return pl && pl->version.uid == uid; });
393                         pos != plugins.end()) {
394                         const auto index = static_cast<size_t>(std::distance(plugins.begin(), pos));
395                         if (--pluginDatas[index].refcnt <= 0) {
396                             recurseRef(plugins, pluginDatas, (*pos)->pluginDependencies, recurseRef);
397                         }
398                     }
399                 }
400             };
401             recurse(plugins, pluginDatas, pluginUids, recurse);
402         }(plugins_, pluginDatas_, pluginUids);
403 
404         auto pdIt = pluginDatas_.crbegin();
405         for (auto pos = plugins_.crbegin(), last = plugins_.crend(); pos != last;) {
406             if (pdIt->refcnt <= 0) {
407                 UnregisterPlugin(*(*pos), pdIt->token);
408                 plugins_.erase(pos.base() - 1);
409                 pluginDatas_.erase(pdIt.base() - 1);
410             }
411             ++pos;
412             ++pdIt;
413         }
414     }
415 }
416 
GetClassRegister() const417 IClassRegister& PluginRegistry::GetClassRegister() const
418 {
419     return *const_cast<PluginRegistry*>(this);
420 }
421 
RegisterTypeInfo(const ITypeInfo & type)422 void PluginRegistry::RegisterTypeInfo(const ITypeInfo& type)
423 {
424     if (const auto pos = typeInfos_.find(type.typeUid); pos != typeInfos_.cend()) {
425         pos->second.push_back(&type);
426     } else {
427         typeInfos_.insert({ type.typeUid, {} }).first->second.push_back(&type);
428     }
429 
430     // During plugin loading gather all the infos and send events once.
431     if (loading_) {
432         newTypeInfos_.push_back(&type);
433     } else {
434         const ITypeInfo* const infos[] = { &type };
435         Notify(typeInfoListeners_, ITypeInfoListener::EventType::ADDED, infos);
436     }
437 }
438 
UnregisterTypeInfo(const ITypeInfo & type)439 void PluginRegistry::UnregisterTypeInfo(const ITypeInfo& type)
440 {
441     if (const auto typeInfos = typeInfos_.find(type.typeUid); typeInfos != typeInfos_.cend()) {
442         auto& infos = typeInfos->second;
443         if (const auto info = std::find(infos.cbegin(), infos.cend(), &type); info != infos.cend()) {
444             infos.erase(info);
445         }
446     }
447 
448     const ITypeInfo* const infos[] = { &type };
449     Notify(typeInfoListeners_, ITypeInfoListener::EventType::REMOVED, infos);
450 }
451 
GetTypeInfos(const Uid & typeUid) const452 array_view<const ITypeInfo* const> PluginRegistry::GetTypeInfos(const Uid& typeUid) const
453 {
454     if (const auto typeInfos = typeInfos_.find(typeUid); typeInfos != typeInfos_.cend()) {
455         return typeInfos->second;
456     }
457     return {};
458 }
459 
AddListener(ITypeInfoListener & listener)460 void PluginRegistry::AddListener(ITypeInfoListener& listener)
461 {
462     if (std::none_of(typeInfoListeners_.begin(), typeInfoListeners_.end(),
463             [adding = &listener](const auto& current) { return current == adding; })) {
464         typeInfoListeners_.push_back(&listener);
465     }
466 }
467 
RemoveListener(const ITypeInfoListener & listener)468 void PluginRegistry::RemoveListener(const ITypeInfoListener& listener)
469 {
470     if (auto pos = std::find(typeInfoListeners_.begin(), typeInfoListeners_.end(), &listener);
471         pos != typeInfoListeners_.end()) {
472         *pos = nullptr;
473     }
474 }
475 
476 // IClassRegister
RegisterInterfaceType(const InterfaceTypeInfo & interfaceInfo)477 void PluginRegistry::RegisterInterfaceType(const InterfaceTypeInfo& interfaceInfo)
478 {
479     // keep interfaceTypeInfos_ sorted according to UIDs
480     const auto pos = std::upper_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), interfaceInfo.uid,
481         [](Uid value, const InterfaceTypeInfo* element) { return value < element->uid; });
482     interfaceTypeInfos_.insert(pos, &interfaceInfo);
483 }
484 
UnregisterInterfaceType(const InterfaceTypeInfo & interfaceInfo)485 void PluginRegistry::UnregisterInterfaceType(const InterfaceTypeInfo& interfaceInfo)
486 {
487     if (!interfaceTypeInfos_.empty()) {
488         const auto pos = std::lower_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), interfaceInfo.uid,
489             [](const InterfaceTypeInfo* element, Uid value) { return element->uid < value; });
490         if ((pos != interfaceTypeInfos_.cend()) && (*pos)->uid == interfaceInfo.uid) {
491             interfaceTypeInfos_.erase(pos);
492         }
493     }
494 }
495 
GetInterfaceMetadata() const496 array_view<const InterfaceTypeInfo* const> PluginRegistry::GetInterfaceMetadata() const
497 {
498     return { interfaceTypeInfos_.data(), interfaceTypeInfos_.size() };
499 }
500 
GetInterfaceMetadata(const Uid & uid) const501 const InterfaceTypeInfo& PluginRegistry::GetInterfaceMetadata(const Uid& uid) const
502 {
503     static constexpr InterfaceTypeInfo invalidType {};
504 
505     if (!interfaceTypeInfos_.empty()) {
506         const auto pos = std::lower_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), uid,
507             [](const InterfaceTypeInfo* element, Uid value) { return element->uid < value; });
508         if ((pos != interfaceTypeInfos_.cend()) && (*pos)->uid == uid) {
509             return *(*pos);
510         }
511     }
512     return invalidType;
513 }
514 
GetInstance(const Uid & uid) const515 IInterface* PluginRegistry::GetInstance(const Uid& uid) const
516 {
517     const auto& data = GetInterfaceMetadata(uid);
518     if (data.getInterface) {
519         return data.getInterface(const_cast<PluginRegistry&>(*this), data.token);
520     }
521     return nullptr;
522 }
523 
524 // IClassFactory
CreateInstance(const Uid & uid)525 IInterface::Ptr PluginRegistry::CreateInstance(const Uid& uid)
526 {
527     const auto& data = GetInterfaceMetadata(uid);
528     if (data.createInterface) {
529         return IInterface::Ptr { data.createInterface(*this, data.token) };
530     }
531     return {};
532 }
533 
534 // IInterface
GetInterface(const Uid & uid) const535 const IInterface* PluginRegistry::GetInterface(const Uid& uid) const
536 {
537     return const_cast<PluginRegistry*>(this)->GetInterface(uid);
538 }
539 
GetInterface(const Uid & uid)540 IInterface* PluginRegistry::GetInterface(const Uid& uid)
541 {
542     if ((uid == IInterface::UID) || (uid == IClassRegister::UID)) {
543         return static_cast<IClassRegister*>(this);
544     }
545     if (uid == IClassFactory::UID) {
546         return static_cast<IClassFactory*>(this);
547     }
548     return nullptr;
549 }
550 
Ref()551 void PluginRegistry::Ref() {}
552 
Unref()553 void PluginRegistry::Unref() {}
554 
555 // Public members
RegisterPluginPath(const string_view path)556 void PluginRegistry::RegisterPluginPath(const string_view path)
557 {
558     if (!fileProtocolRegistered_) {
559         fileProtocolRegistered_ = true;
560         fileManager_.RegisterFilesystem("file", IFilesystem::Ptr { new StdFilesystem("/") });
561     }
562     fileManager_.RegisterPath("plugins", path, false);
563 }
564 
GetFileManager()565 IFileManager& PluginRegistry::GetFileManager()
566 {
567     return fileManager_;
568 }
569 
570 // Private members
RegisterPlugin(ILibrary::Ptr lib,const IPlugin & plugin,bool asDependency)571 void PluginRegistry::RegisterPlugin(ILibrary::Ptr lib, const IPlugin& plugin, bool asDependency)
572 {
573     CORE_LOG_D("\tRegister Plugin: %s %s", plugin.name, to_string(plugin.version.uid).data());
574     if (plugin.version.GetVersionString) {
575         CORE_LOG_D("\tVersion Info: %s", plugin.version.GetVersionString());
576     }
577     if (std::any_of(plugins_.begin(), plugins_.end(),
578             [&plugin](const IPlugin* pl) { return strcmp(plugin.name, pl->name) == 0; })) {
579         CORE_LOG_W("\tSkipping duplicate plugin: %s!", plugin.name);
580         return;
581     }
582     // when a plugin is loaded/ registered due a requested plugin depends on it ref count starts from zero and it's
583     // expected that some following plugin will place a reference. once that plugin releases its reference the
584     // dependency is known to be a candidate for unloading.
585     PluginData pd { move(lib), {}, asDependency ? 0 : 1 };
586     if (plugin.registerInterfaces) {
587         pd.token = plugin.registerInterfaces(*static_cast<IPluginRegister*>(this));
588     }
589 
590     pluginDatas_.push_back(move(pd));
591     plugins_.push_back(&plugin);
592     for (const auto& dependency : plugin.pluginDependencies) {
593         if (auto pos = std::find_if(plugins_.begin(), plugins_.end(),
594                 [dependency](const IPlugin* plugin) { return plugin->version.uid == dependency; });
595             pos != plugins_.end()) {
596             const auto index = static_cast<size_t>(std::distance(plugins_.begin(), pos));
597             ++pluginDatas_[index].refcnt;
598         }
599     }
600 }
601 
UnregisterPlugin(const IPlugin & plugin,PluginToken token)602 void PluginRegistry::UnregisterPlugin(const IPlugin& plugin, PluginToken token)
603 {
604     CORE_LOG_D("\tUnregister Plugin: %s %s", plugin.name, to_string(plugin.version.uid).data());
605 
606     if (plugin.unregisterInterfaces) {
607         plugin.unregisterInterfaces(token);
608     }
609 }
610 
611 // Library exports
GetPluginRegister()612 CORE_PUBLIC IPluginRegister& GetPluginRegister()
613 {
614     static PluginRegistry registry;
615     return registry;
616 }
617 
CreatePluginRegistry(const PlatformCreateInfo & platformCreateInfo)618 CORE_PUBLIC void CreatePluginRegistry(const PlatformCreateInfo& platformCreateInfo)
619 {
620     static bool once = false;
621     if (!once) {
622         once = true;
623         auto& registry = static_cast<PluginRegistry&>(GetPluginRegister());
624         // Create plugins:// protocol that points to plugin files.
625         // register path to system plugins
626         // Root path is the location where system plugins , non-rofs assets etc could be held.
627         auto platform = Platform::Create(platformCreateInfo);
628         platform->RegisterPluginLocations(registry);
629     }
630 }
631 CORE_END_NAMESPACE()
632