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 { ®istry, UID_LOGGER, GetName<ILogger>().data(), nullptr,
210 [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
211 return &static_cast<PluginRegistry*>(token)->logger_;
212 } },
213 InterfaceTypeInfo { ®istry, UID_FRUSTUM_UTIL, GetName<IFrustumUtil>().data(), nullptr,
214 [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
215 return &static_cast<PluginRegistry*>(token)->frustumUtil_;
216 } },
217 InterfaceTypeInfo { ®istry, 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 { ®istry, UID_SYSTEM_GRAPH_LOADER, GetName<ISystemGraphLoaderFactory>().data(), nullptr,
222 [](IClassRegister& /* registry */, PluginToken token) -> IInterface* {
223 return &static_cast<PluginRegistry*>(token)->systemGraphLoadeFactory;
224 } },
225 InterfaceTypeInfo { ®istry, UID_GLOBAL_FACTORY, "Global registry factory", nullptr,
226 [](IClassRegister& registry, PluginToken /* token */) -> IInterface* {
227 return registry.GetInterface<IClassFactory>();
228 } },
229 InterfaceTypeInfo {
230 ®istry, UID_FILESYSTEM_API_FACTORY, "Filesystem API factory", nullptr, GetFileApiFactory },
231 InterfaceTypeInfo { ®istry, UID_FILE_MONITOR, "Filemonitor", CreateFileMonitor, nullptr },
232 InterfaceTypeInfo { ®istry, UID_FILE_MANAGER, "FileManager",
233 [](IClassFactory& /* factory */, PluginToken /* token */) -> IInterface* {
234 return new CORE_NS::FileManager();
235 },
236 nullptr },
237 InterfaceTypeInfo { ®istry, 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 { ®istry, 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