2 * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file plugin_installer.cpp
18 * @author Andrzej Surdej(a.surdej@samgsung.com)
23 #include "plugin_installer.h"
30 #include <vcore/VCore.h>
31 #include <libxml/parser.h>
33 #include "plugin_objects.h"
34 #include "plugin_metafile_reader.h"
35 #include "plugin_installer_errors.h"
38 #include <IObject_cast.h>
39 #include <plugin_utils.h>
40 #include <ExportedApi.h>
42 #include <wrt-commons/wrt_plugin_export.h>
44 #include <dpl/log/log.h>
45 #include <dpl/exception.h>
46 #include <dpl/wrt-dao-ro/global_config.h>
47 #include <dpl/wrt-dao-rw/plugin_dao.h>
48 #include <dpl/wrt-dao-rw/feature_dao.h>
49 #include <dpl/foreach.h>
50 #include <dpl/wrt-dao-ro/WrtDatabase.h>
52 #include <dpl/singleton_impl.h>
54 using namespace WrtDB;
55 using namespace WrtPluginsApi;
57 IMPLEMENT_SINGLETON(PluginsInstaller)
60 const std::string DIRECTORY_SEPARATOR = std::string("/");
63 const int PluginsInstaller::INSTALLATION_ERROR = -1;
65 PluginsInstaller::PluginsInstaller() :
68 LogDebug("PluginsInstaller created.");
70 PluginsInstaller::~PluginsInstaller()
72 LogDebug("PluginsInstaller destroyed.");
75 void PluginsInstaller::checkDatabaseTablesExistance()
77 if (!WrtDB::WrtDatabase::CheckTableExist("FeaturesList") ||
78 !WrtDB::WrtDatabase::CheckTableExist("PluginProperties") ||
79 !WrtDB::WrtDatabase::CheckTableExist("PluginDependencies") ||
80 !WrtDB::WrtDatabase::CheckTableExist("PluginImplementedObjects") ||
81 !WrtDB::WrtDatabase::CheckTableExist("PluginRequiredObjects") ||
82 !WrtDB::WrtDatabase::CheckTableExist("DeviceCapabilities") ||
83 !WrtDB::WrtDatabase::CheckTableExist("FeatureDeviceCapProxy"))
85 LogError("Wrong database. Required tables not exist.");
87 Assert(false && "Wrong database. Required tables not exist.");
91 bool PluginsInstaller::initialize()
93 LogDebug("Initializing required systems.");
96 if (!PluginUtils::checkPaths()) {
99 // Initialize ValidationCore - this must be done before AttachDatabases
100 ValidationCore::VCoreInit(
101 std::string(GlobalConfig::GetFingerprintListFile()),
102 std::string(GlobalConfig::GetFingerprintListSchema()),
103 std::string(GlobalConfig::GetVCoreDatabaseFilePath()));
106 WrtDB::WrtDatabase::attachToThreadRW();
107 ValidationCore::AttachToThreadRW();
108 checkDatabaseTablesExistance();
109 LogDebug("Initialized.");
110 m_initialized = true;
114 void PluginsInstaller::deinitialize()
116 LogDebug("Shuting systems down.");
117 m_initialized = false;
118 ValidationCore::DetachFromThread();
119 WrtDB::WrtDatabase::detachFromThread();
120 ValidationCore::VCoreDeinit();
125 PluginsInstaller::ReturnStatus PluginsInstaller::installPlugin(
126 const std::string& libPath)
128 if (!m_initialized) {
129 LogError("Plugins installer not initialized.");
130 return ReturnStatus::NotInitialized;
132 LogDebug("Plugin installation started. Checking path: " << libPath);
134 if (!PluginUtils::checkPath(libPath)) {
135 return ReturnStatus::WrongPluginPath;
138 LogDebug("Plugin path ok. Searching for config file...");
140 std::string metaFileName = libPath + DIRECTORY_SEPARATOR +
141 std::string(WrtDB::GlobalConfig::GetPluginMetafileName());
142 if (PluginUtils::checkFileExistance(metaFileName)) {
143 return installPluginFromMetafile(libPath, metaFileName);
146 PluginMetafileData pluginInfo;
147 pluginInfo.m_libraryName = getLibraryName(libPath);
150 "Config file done. Lib name: " << pluginInfo.m_libraryName
152 ". Searching for installed plugin...");
154 if (WrtDB::PluginDAO::isPluginInstalled(pluginInfo.m_libraryName)) {
155 LogDebug("Plugin already installed.");
156 return ReturnStatus::AlreadyInstalled;
158 LogDebug("Plugin not installed. Loading library file...");
160 PluginObjectsPtr libraryObjects;
161 PluginHandle pluginHandle;
163 std::string filename = libPath + DIRECTORY_SEPARATOR +
164 pluginInfo.m_libraryName;
166 LogDebug("Loading plugin: " << filename);
171 plugin = m_registry.GetPlugin(filename);
173 Catch(DPL::Exception) {
174 LogError("Loading library failed " << filename);
175 return ReturnStatus::LoadingLibraryError;
177 libraryObjects = PluginObjectsPtr(new PluginObjects());
180 LogDebug("##### Plugin: " << filename << " supports new plugin API");
183 FOREACH(o, *plugin->GetObjects()) {
184 libraryObjects->addObjects(CAST(*o)->GetParentName(),
185 CAST(*o)->GetName());
187 LogDebug("[Parent << Object] " << CAST(*o)->GetParentName()
189 << CAST(*o)->GetName());
191 registerObjects(libraryObjects, plugin->GetObjects());
194 if (!fillMappingInterfaces(pluginInfo, filename)) {
195 m_registry.RemovePlugin(filename, *plugin);
196 return ReturnStatus::LoadingLibraryError;
199 LogDebug("Library loaded. Registering plugin...");
204 PluginDAO::registerPlugin(pluginInfo, libPath);
206 LogDebug("Plugin registered. Registering features...");
208 FOREACH(it, pluginInfo.m_featureContainer)
210 LogError("PluginHandle: " << pluginHandle);
211 FeatureDAO::RegisterFeature(*it, pluginHandle);
214 LogDebug("Features registered. Registering objects...");
216 registerPluginObjects(pluginHandle, libraryObjects);
218 LogDebug("Registration done. Resolving dependencies...");
220 //TODO: can it be replaced with resolvePluginDependencies(handle)
221 if (!registerAndUpdateInstallation(pluginHandle, libraryObjects)) {
222 return ReturnStatus::InstallationWaiting;
224 } Catch(DPL::Exception) {
225 LogError("Failed to make database entry.");
226 return ReturnStatus::DatabaseError;
229 LogDebug("Plugin installed successfully.");
230 return ReturnStatus::Success;
233 PluginObjectsPtr PluginsInstaller::loadLibraryFromMetafile(
234 const std::string& libName) const
236 LogDebug("Loading library: " << libName);
238 void *dlHandle = dlopen(libName.c_str(), RTLD_NOW);
239 if (dlHandle == NULL) {
240 const char* error = (const char*)dlerror();
242 "Failed to load plugin: " << libName <<
243 ". Reason: " << (error != NULL ? error : "unknown"));
244 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
247 const js_entity_definition_t *rawEntityList = NULL;
248 get_widget_entity_map_proc *getWidgetEntityMapProcPtr = NULL;
250 getWidgetEntityMapProcPtr =
251 reinterpret_cast<get_widget_entity_map_proc *>(dlsym(dlHandle,
252 PLUGIN_GET_CLASS_MAP_PROC_NAME));
254 if (getWidgetEntityMapProcPtr) {
255 rawEntityList = (*getWidgetEntityMapProcPtr)();
258 static_cast<const js_entity_definition_t *>(dlsym(dlHandle,
259 PLUGIN_CLASS_MAP_NAME));
262 if (rawEntityList == NULL) {
264 LogError("Failed to read class name" << libName);
265 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
268 PluginObjectsPtr libraryObjects = PluginObjectsPtr(new PluginObjects());
269 const js_entity_definition_t *rawEntityListIterator = rawEntityList;
272 LogDebug("##### Plugin: " << libName << " is using deprecated API");
275 while (rawEntityListIterator->parent_name != NULL &&
276 rawEntityListIterator->object_name != NULL)
278 LogDebug("##### [" << rawEntityListIterator->object_name << "]: ");
279 LogDebug("##### Parent: " << rawEntityListIterator->parent_name);
282 libraryObjects->addObjects(rawEntityListIterator->parent_name,
283 rawEntityListIterator->object_name);
285 ++rawEntityListIterator;
289 if (dlclose(dlHandle) != 0) {
290 LogError("Cannot close plugin handle");
292 LogDebug("Library is unloaded");
296 LogDebug("Library successfuly loaded and parsed");
298 return libraryObjects;
301 PluginsInstaller::ReturnStatus PluginsInstaller::installPluginFromMetafile(
302 const std::string& path, const std::string& metaFilePath)
304 if (!m_initialized) {
305 LogError("Plugins installer not initialized.");
306 return ReturnStatus::NotInitialized;
308 OptionalPluginMetafileData pluginData;
311 pluginData = parseMetafile(metaFilePath);
313 Catch(PluginInstall::Exceptions::XMLFileParsingException)
315 LogError("Parsing metafile failed.");
316 return ReturnStatus::MetafileError;
319 return ReturnStatus::MetafileError;
322 if (WrtDB::PluginDAO::isPluginInstalled(pluginData->m_libraryName)) {
323 LogDebug("Plugin already installed.");
324 return ReturnStatus::AlreadyInstalled;
328 "path is: " << path << ", libraryName: " <<
329 pluginData->m_libraryName);
330 PluginObjectsPtr objects = loadLibraryFromMetafile(
331 path + DIRECTORY_SEPARATOR + pluginData->m_libraryName);
333 PluginHandle pluginHandle =
334 PluginDAO::registerPlugin(*pluginData, path);
336 LogDebug("Plugin registered. Registering features...");
338 FOREACH(it, pluginData->m_featureContainer)
340 LogError("PluginHandle: " << pluginHandle);
341 FeatureDAO::RegisterFeature(*it, pluginHandle);
344 LogDebug("Features registered. Registering objects...");
346 registerPluginObjects(pluginHandle, objects);
348 LogDebug("Objects registered. Finishing...");
350 if (!registerAndUpdateInstallation(pluginHandle, objects)) {
351 return ReturnStatus::InstallationWaiting;
353 } Catch(DPL::Exception) {
354 LogError("Failed to make database entry.");
355 return ReturnStatus::DatabaseError;
358 LogDebug("Plugin installed successfully.");
359 return ReturnStatus::Success;
362 int PluginsInstaller::installAllPlugins()
364 if (!m_initialized) {
365 LogError("Plugins installer not initialized.");
366 return INSTALLATION_ERROR;
368 LogDebug("Installing plugins ...");
370 std::string PLUGIN_PATH = std::string(GlobalConfig::GetDevicePluginPath());
373 dir = opendir(PLUGIN_PATH.c_str());
376 return INSTALLATION_ERROR;
379 LogDebug("Plugin DIRECTORY IS" << PLUGIN_PATH);
381 struct dirent libdir;
382 struct dirent* result;
386 std::list<std::string> pluginsPaths;
388 for (return_code = readdir_r(dir, &libdir, &result);
389 result != NULL && return_code == 0;
390 return_code = readdir_r(dir, &libdir, &result)) {
391 if (strcmp(libdir.d_name, ".") == 0 ||
392 strcmp(libdir.d_name, "..") == 0)
397 std::string path = PLUGIN_PATH;
399 path += libdir.d_name;
403 if (stat(path.c_str(), &tmp) == -1) {
404 LogError("Failed to open file" << path);
408 if (!S_ISDIR(tmp.st_mode)) {
409 LogError("Not a directory" << path);
413 LogDebug("Found plugin at " << path);
414 pluginsPaths.push_back(path);
417 if (0 != return_code)
418 LogError("Error while reading directory.");
420 if (-1 == closedir(dir)) {
421 LogError("Failed to close dir: " << PLUGIN_PATH);
424 LogDebug("Plugins to install: " << pluginsPaths.size());
426 for (size_t k = 0; k <= pluginsPaths.size(); ++k) {
430 int installedPluginsCount = 0;
431 ReturnStatus ret = ReturnStatus::Unknown;
432 FOREACH(it, pluginsPaths) {
433 LogDebug("Preparing to plugin installation: " << *it);
434 ret = installPlugin(*it);
435 if (ReturnStatus::Success == ret) {
436 ++installedPluginsCount;
437 LogDebug("Plugin " << *it << " installed.");
438 } else if (ReturnStatus::InstallationWaiting == ret) {
439 LogWarning("Plugin not installed. Waiting for dependency");
441 LogError("Plugin installation failed");
447 installedPluginsCount += installWaitingPlugins();
448 m_registry.UnloadAll();
449 LogDebug("Installed " << installedPluginsCount
450 << " plugins of total: " << pluginsPaths.size());
451 return installedPluginsCount;
454 int PluginsInstaller::installWaitingPlugins()
456 PluginHandleSetPtr waitingPlugins;
459 PluginDAO::getPluginHandleByStatus(PluginDAO::INSTALLATION_WAITING);
461 int pluginsInstalled = 0;
462 FOREACH(it, *waitingPlugins)
464 if (resolvePluginDependencies(*it)) {
468 return pluginsInstalled;
471 bool PluginsInstaller::resolvePluginDependencies(PluginHandle handle)
473 PluginHandleSetPtr dependencies(new PluginHandleSet);
475 PluginObjects::ObjectsPtr requiredObjects =
476 PluginDAO::getRequiredObjectsForPluginHandle(handle);
478 PluginHandle depHandle = INVALID_PLUGIN_HANDLE;
480 FOREACH(requiredObject, *requiredObjects)
483 PluginDAO::getPluginHandleForImplementedObject(*requiredObject);
485 if (INVALID_PLUGIN_HANDLE == depHandle) {
486 LogError("Library implementing: " <<
487 *requiredObject << " NOT FOUND");
490 dependencies->insert(depHandle);
493 PluginDAO::registerPluginLibrariesDependencies(handle, dependencies);
494 PluginDAO::setPluginInstallationStatus(handle,
495 PluginDAO::INSTALLATION_COMPLETED);
500 void PluginsInstaller::registerObjects(const PluginObjectsPtr& libObj,
501 const IObjectsListPtr& objects) const
503 LogDebug("registerObjects invoked");
507 auto children = CAST(*o)->GetChildren();
510 FOREACH(c, *children)
512 libObj->addObjects(CAST(*o)->GetName(), CAST(*c)->GetName());
514 LogDebug("[Parent << Object] " << CAST(*c)->GetName()
516 << CAST(*o)->GetName());
519 registerObjects(libObj, children);
524 PluginsInstaller::OptionalPluginMetafileData PluginsInstaller::parseMetafile(
525 const std::string& path) const
527 LogDebug("Plugin Config file::" << path);
530 PluginMetafileData pluginInfo;
531 PluginMetafileReader reader;
532 reader.initialize(path);
533 reader.read(pluginInfo);
535 FOREACH(it, pluginInfo.m_featureContainer) {
536 LogDebug("Parsed feature : " << it->m_name);
538 FOREACH(devCap, it->m_deviceCapabilities) {
539 LogDebug(" | DevCap : " << *devCap);
542 return OptionalPluginMetafileData(pluginInfo);
544 Catch(ValidationCore::ParserSchemaException::Base) {
545 LogError("Error during file processing " << path);
546 ThrowMsg(PluginInstall::Exceptions::XMLFileParsingException,
547 "Parsing metafile failed");
551 std::string PluginsInstaller::getLibraryName(const std::string& dirPath) const
553 std::string pluginPath = dirPath;
554 size_t indexpos = pluginPath.find_last_of('/');
556 if (std::string::npos == indexpos) {
559 indexpos += 1; // move after '/'
562 std::string libName = pluginPath.substr(indexpos);
563 libName = WrtDB::GlobalConfig::GetPluginPrefix() + libName
564 + WrtDB::GlobalConfig::GetPluginSuffix();
565 LogDebug("Plugin .so: " << libName);
569 bool PluginsInstaller::registerAndUpdateInstallation(
570 const WrtDB::DbPluginHandle& pluginHandle,
571 const PluginObjectsPtr& libraries)
573 PluginHandleSetPtr handles = PluginHandleSetPtr(new PluginHandleSet);
575 DbPluginHandle handle = INVALID_PLUGIN_HANDLE;
577 //register requiredObjects
578 FOREACH(it, *(libraries->getDependentObjects()))
580 if (libraries->hasObject(*it)) {
581 LogDebug("Dependency from the same library. ignored");
585 handle = PluginDAO::getPluginHandleForImplementedObject(*it);
586 if (handle == INVALID_PLUGIN_HANDLE) {
587 LogError("Library implementing: " << *it << " NOT FOUND");
588 PluginDAO::setPluginInstallationStatus(
590 PluginDAO::INSTALLATION_WAITING);
594 handles->insert(handle);
597 PluginDAO::registerPluginLibrariesDependencies(pluginHandle, handles);
599 PluginDAO::setPluginInstallationStatus(pluginHandle,
600 PluginDAO::INSTALLATION_COMPLETED);
604 bool PluginsInstaller::fillMappingInterfaces(PluginMetafileData& pluginData,
605 const std::string& filename)
607 void *dlHandle = dlopen(filename.c_str(), RTLD_NOW);
608 if (dlHandle == NULL) {
609 const char* error = (const char*)dlerror();
611 "Failed to load plugin: " << filename << ". Reason: " << (error != NULL ? error : "unknown"));
616 ExportedApi* entryPoint =
617 static_cast<ExportedApi*>(dlsym(dlHandle, GetExportedSymbolName()));
618 if (NULL == entryPoint) {
619 const char* error = (const char*)dlerror();
620 LogError("Error: " << (error != NULL ? error : "unknown"));
621 ThrowMsg(PluginInstall::Exceptions::LibraryException,
625 // obtain feature -> dev-cap mapping
626 feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
627 entryPoint->GetProvidedFeatures(&mappingInterface);
629 if (!mappingInterface.featGetter || !mappingInterface.release ||
630 !mappingInterface.dcGetter)
632 LogError("Failed to obtain mapping interface from .so");
633 ThrowMsg(PluginInstall::Exceptions::LibraryException,
637 feature_mapping_t* devcapMapping = mappingInterface.featGetter();
639 LogDebug("Getting mapping from features to device capabilities");
641 for (size_t i = 0; i < devcapMapping->featuresCount; ++i) {
642 PluginMetafileData::Feature feature;
643 feature.m_name = devcapMapping->features[i].feature_name;
645 LogDebug("Feature: " << feature.m_name);
647 const devcaps_t* dc =
648 mappingInterface.dcGetter(
650 devcapMapping->features[i].
653 LogDebug("device=cap: " << dc);
656 LogDebug("devcaps count: " << dc->devCapsCount);
658 for (size_t j = 0; j < dc->devCapsCount; ++j) {
659 LogDebug("devcap: " << dc->deviceCaps[j]);
660 feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
664 pluginData.m_featureContainer.insert(feature);
667 mappingInterface.release(devcapMapping);
668 } Catch(PluginInstall::Exceptions::PluginsInstallerException)
670 LogError("Exception while feature mapping");
676 if (dlclose(dlHandle) != 0) {
677 LogError("Cannot close plugin handle");
679 LogDebug("Library is unloaded");
684 void PluginsInstaller::registerPluginObjects(
685 const WrtDB::DbPluginHandle& handle,
686 const PluginObjectsPtr libObjects)
689 //register implemented objects
690 PluginObjects::ObjectsPtr objects =
691 libObjects->getImplementedObject();
693 FOREACH(it, *objects)
695 WrtDB::PluginDAO::registerPluginImplementedObject(*it, handle);
698 //register requiredObjects
699 objects = libObjects->getDependentObjects();
701 FOREACH(it, *objects)
703 if (libObjects->hasObject(*it)) {
704 LogDebug("Dependency from the same library. ignored");
707 WrtDB::PluginDAO::registerPluginRequiredObject(*it, handle);