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 <SoFeatures.h>
40 #include <plugin_utils.h>
41 #include <ExportedApi.h>
43 #include <wrt-commons/wrt_plugin_export.h>
45 #include <dpl/log/log.h>
46 #include <dpl/exception.h>
47 #include <dpl/wrt-dao-ro/global_config.h>
48 #include <dpl/wrt-dao-rw/plugin_dao.h>
49 #include <dpl/wrt-dao-rw/feature_dao.h>
50 #include <dpl/foreach.h>
51 #include <dpl/wrt-dao-ro/WrtDatabase.h>
53 #include <dpl/singleton_impl.h>
55 using namespace WrtDB;
56 using namespace WrtPluginsApi;
58 IMPLEMENT_SINGLETON(PluginsInstaller)
61 const std::string DIRECTORY_SEPARATOR = std::string("/");
64 const int PluginsInstaller::INSTALLATION_ERROR = -1;
66 PluginsInstaller::PluginsInstaller()
67 : m_initialized(false)
69 LogInfo("PluginsInstaller created.");
71 PluginsInstaller::~PluginsInstaller()
73 LogInfo("PluginsInstaller destroyed.");
76 void PluginsInstaller::checkDatabaseTablesExistance()
78 if (!WrtDB::WrtDatabase::CheckTableExist("FeaturesList") ||
79 !WrtDB::WrtDatabase::CheckTableExist("PluginProperties") ||
80 !WrtDB::WrtDatabase::CheckTableExist("PluginDependencies") ||
81 !WrtDB::WrtDatabase::CheckTableExist("PluginImplementedObjects") ||
82 !WrtDB::WrtDatabase::CheckTableExist("PluginRequiredObjects") ||
83 !WrtDB::WrtDatabase::CheckTableExist("DeviceCapabilities") ||
84 !WrtDB::WrtDatabase::CheckTableExist("FeatureDeviceCapProxy"))
86 LogError("Wrong database. Required tables not exist.");
88 Assert(false && "Wrong database. Required tables not exist.");
92 bool PluginsInstaller::initialize()
94 LogDebug("Initializing required systems.");
97 if (!PluginUtils::checkPaths()) {
100 // Initialize ValidationCore - this must be done before AttachDatabases
101 ValidationCore::VCoreInit(
102 std::string(GlobalConfig::GetFingerprintListFile()),
103 std::string(GlobalConfig::GetFingerprintListSchema()),
104 std::string(GlobalConfig::GetVCoreDatabaseFilePath()));
107 WrtDB::WrtDatabase::attachToThreadRW();
108 ValidationCore::AttachToThreadRW();
109 checkDatabaseTablesExistance();
110 LogDebug("Initialized.");
111 m_initialized = true;
115 void PluginsInstaller::deinitialize()
117 LogDebug("Shuting systems down.");
118 m_initialized = false;
119 ValidationCore::DetachFromThread();
120 WrtDB::WrtDatabase::detachFromThread();
121 ValidationCore::VCoreDeinit();
126 PluginsInstaller::ReturnStatus PluginsInstaller::installPlugin(
127 const std::string& libPath)
129 if (!m_initialized) {
130 LogError("Plugins installer not initialized.");
131 return ReturnStatus::NotInitialized;
133 LogInfo("Plugin installation started. Checking path: " << libPath);
135 if (!PluginUtils::checkPath(libPath))
136 return ReturnStatus::WrongPluginPath;
138 LogInfo("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))
144 return installPluginFromMetafile(libPath, metaFileName);
147 PluginMetafileData pluginInfo;
148 pluginInfo.m_libraryName = getLibraryName(libPath);
150 LogInfo("Config file done. Lib name: " << pluginInfo.m_libraryName
151 << ". Searching for installed plugin...");
153 if (WrtDB::PluginDAO::isPluginInstalled(pluginInfo.m_libraryName)) {
154 LogInfo("Plugin already installed.");
155 return ReturnStatus::AlreadyInstalled;
157 LogInfo("Plugin not installed. Loading library file...");
159 PluginObjectsPtr libraryObjects;
160 PluginHandle pluginHandle;
162 std::string filename = libPath + DIRECTORY_SEPARATOR +
163 pluginInfo.m_libraryName;
165 LogDebug("Loading plugin: " << filename);
170 plugin = m_registry.GetPlugin(filename);
172 Catch(DPL::Exception) {
173 LogError("Loading library failed " << filename);
174 return ReturnStatus::LoadingLibraryError;
176 libraryObjects = PluginObjectsPtr(new PluginObjects());
179 LogInfo("##### Plugin: " << filename << " supports new plugin API");
182 FOREACH(o, *plugin->GetObjects()) {
183 libraryObjects->addObjects(CAST(*o)->GetParentName(),
184 CAST(*o)->GetName());
186 LogDebug("[Parent << Object] " << CAST(*o)->GetParentName()
188 << CAST(*o)->GetName());
190 registerObjects(libraryObjects, plugin->GetObjects());
193 if (!fillMappingInterfaces(pluginInfo, filename)) {
194 m_registry.RemovePlugin(filename, *plugin);
195 return ReturnStatus::LoadingLibraryError;
198 LogInfo("Library loaded. Registering plugin...");
203 PluginDAO::registerPlugin(pluginInfo, libPath);
205 LogInfo("Plugin registered. Registering features...");
207 FOREACH(it, pluginInfo.m_featureContainer)
209 LogError("PluginHandle: " << pluginHandle);
210 FeatureDAO::RegisterFeature(*it, pluginHandle);
213 LogInfo("Features registered. Registering objects...");
215 registerPluginObjects(pluginHandle, libraryObjects);
217 LogInfo("Registration done. Resolving dependencies...");
219 //TODO: can it be replaced with resolvePluginDependencies(handle)
220 if (!registerAndUpdateInstallation(pluginHandle, libraryObjects))
221 return ReturnStatus::InstallationWaiting;
222 } Catch (DPL::Exception) {
223 LogError("Failed to make database entry.");
224 return ReturnStatus::DatabaseError;
227 LogInfo("Plugin installed successfully.");
228 return ReturnStatus::Success;
231 PluginObjectsPtr PluginsInstaller::loadLibraryFromMetafile(
232 const std::string& libName) const
234 LogInfo("Loading library: " << libName);
236 void *dlHandle = dlopen(libName.c_str(), RTLD_NOW);
237 if (dlHandle == NULL ) {
239 "Failed to load plugin: " << libName <<
240 ". Reason: " << dlerror());
241 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
244 const js_entity_definition_t *rawEntityList = NULL;
245 get_widget_entity_map_proc *getWidgetEntityMapProcPtr = NULL;
247 getWidgetEntityMapProcPtr =
248 reinterpret_cast<get_widget_entity_map_proc *>(dlsym(dlHandle,
249 PLUGIN_GET_CLASS_MAP_PROC_NAME));
251 if (getWidgetEntityMapProcPtr) {
252 rawEntityList = (*getWidgetEntityMapProcPtr)();
255 static_cast<const js_entity_definition_t *>(dlsym(dlHandle,
256 PLUGIN_CLASS_MAP_NAME));
259 if (rawEntityList == NULL) {
261 LogError("Failed to read class name" << libName);
262 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
265 PluginObjectsPtr libraryObjects = PluginObjectsPtr(new PluginObjects());
266 const js_entity_definition_t *rawEntityListIterator = rawEntityList;
269 LogInfo("##### Plugin: " << libName << " is using deprecated API");
272 while (rawEntityListIterator->parent_name != NULL &&
273 rawEntityListIterator->object_name != NULL)
275 LogInfo("##### [" << rawEntityListIterator->object_name << "]: ");
276 LogInfo("##### Parent: " << rawEntityListIterator->parent_name);
279 libraryObjects->addObjects(rawEntityListIterator->parent_name,
280 rawEntityListIterator->object_name);
282 ++rawEntityListIterator;
286 if (dlclose(dlHandle) != 0) {
287 LogError("Cannot close plugin handle");
289 LogDebug("Library is unloaded");
293 LogDebug("Library successfuly loaded and parsed");
295 return libraryObjects;
299 PluginsInstaller::ReturnStatus PluginsInstaller::installPluginFromMetafile(
300 const std::string& path, const std::string& metaFilePath)
302 if (!m_initialized) {
303 LogError("Plugins installer not initialized.");
304 return ReturnStatus::NotInitialized;
306 OptionalPluginMetafileData pluginData;
309 pluginData = parseMetafile(metaFilePath);
311 Catch (PluginInstall::Exceptions::XMLFileParsingException)
313 LogError("Parsing metafile failed.");
314 return ReturnStatus::MetafileError;
316 if (pluginData.IsNull()) {
317 return ReturnStatus::MetafileError;
320 if (WrtDB::PluginDAO::isPluginInstalled(pluginData->m_libraryName)) {
321 LogInfo("Plugin already installed.");
322 return ReturnStatus::AlreadyInstalled;
326 LogError("path is: " << path << ", libraryName: " << pluginData->m_libraryName);
327 PluginObjectsPtr objects = loadLibraryFromMetafile(
328 path + DIRECTORY_SEPARATOR + pluginData->m_libraryName);
330 PluginHandle pluginHandle =
331 PluginDAO::registerPlugin(*pluginData, path);
333 LogInfo("Plugin registered. Registering features...");
335 FOREACH(it, pluginData->m_featureContainer)
337 LogError("PluginHandle: " << pluginHandle);
338 FeatureDAO::RegisterFeature(*it, pluginHandle);
341 LogInfo("Features registered. Registering objects...");
343 registerPluginObjects(pluginHandle, objects);
345 LogInfo("Objects registered. Finishing...");
347 if (!registerAndUpdateInstallation(pluginHandle, objects))
348 return ReturnStatus::InstallationWaiting;
349 } Catch (DPL::Exception) {
350 LogError("Failed to make database entry.");
351 return ReturnStatus::DatabaseError;
354 LogInfo("Plugin installed successfully.");
355 return ReturnStatus::Success;
358 int PluginsInstaller::installAllPlugins()
360 if (!m_initialized) {
361 LogError("Plugins installer not initialized.");
362 return INSTALLATION_ERROR;
364 LogDebug("Installing plugins ...");
366 std::string PLUGIN_PATH = std::string(GlobalConfig::GetDevicePluginPath());
369 dir = opendir(PLUGIN_PATH.c_str());
372 return INSTALLATION_ERROR;
375 LogInfo("Plugin DIRECTORY IS" << PLUGIN_PATH);
376 struct dirent* libdir;
380 std::list<std::string> pluginsPaths;
382 while ((libdir = readdir(dir)) != 0) {
383 if (strcmp(libdir->d_name, ".") == 0 ||
384 strcmp(libdir->d_name, "..") == 0) {
388 std::string path = PLUGIN_PATH;
390 path += libdir->d_name;
394 if (stat(path.c_str(), &tmp) == -1) {
395 LogError("Failed to open file" << path);
399 if (!S_ISDIR(tmp.st_mode)) {
400 LogError("Not a directory" << path);
404 LogDebug("Found plugin at " << path);
405 pluginsPaths.push_back(path);
408 if (-1 == TEMP_FAILURE_RETRY(closedir(dir))) {
409 LogError("Failed to close dir: " << PLUGIN_PATH);
412 LogDebug("Plugins to install: " << pluginsPaths.size());
414 for (int k = 0; k <= pluginsPaths.size(); ++k)
417 int installedPluginsCount = 0;
418 ReturnStatus ret = ReturnStatus::Unknown;
419 FOREACH(it, pluginsPaths) {
420 LogInfo("Preparing to plugin installation: " << *it);
421 ret = installPlugin(*it);
422 if (ReturnStatus::Success == ret) {
423 ++installedPluginsCount;
424 LogInfo("Plugin " << *it << " installed.");
425 } else if (ReturnStatus::InstallationWaiting == ret) {
426 LogWarning("Plugin not installed. Waiting for dependency");
428 LogError("Plugin installation failed");
434 installedPluginsCount += installWaitingPlugins();
435 m_registry.UnloadAll();
436 LogInfo("Installed " << installedPluginsCount
437 << " plugins of total: " << pluginsPaths.size());
438 return installedPluginsCount;
441 int PluginsInstaller::installWaitingPlugins()
443 PluginHandleSetPtr waitingPlugins;
446 PluginDAO::getPluginHandleByStatus(PluginDAO::INSTALLATION_WAITING);
448 int pluginsInstalled = 0;
449 FOREACH(it, *waitingPlugins)
451 if (resolvePluginDependencies(*it))
454 return pluginsInstalled;
457 bool PluginsInstaller::resolvePluginDependencies(PluginHandle handle)
459 PluginHandleSetPtr dependencies(new PluginHandleSet);
461 PluginObjects::ObjectsPtr requiredObjects =
462 PluginDAO::getRequiredObjectsForPluginHandle(handle);
464 PluginHandle depHandle = INVALID_PLUGIN_HANDLE;
466 FOREACH(requiredObject, *requiredObjects)
469 PluginDAO::getPluginHandleForImplementedObject(*requiredObject);
471 if (INVALID_PLUGIN_HANDLE == depHandle) {
472 LogError("Library implementing: " <<
473 *requiredObject << " NOT FOUND");
476 dependencies->insert(depHandle);
479 PluginDAO::registerPluginLibrariesDependencies(handle, dependencies);
480 PluginDAO::setPluginInstallationStatus(handle,
481 PluginDAO::INSTALLATION_COMPLETED);
486 void PluginsInstaller::registerObjects(const PluginObjectsPtr& libObj,
487 const IObjectsListPtr& objects) const
489 LogDebug("registerObjects invoked");
493 auto children = CAST(*o)->GetChildren();
497 FOREACH(c, *children)
499 libObj->addObjects(CAST(*o)->GetName(), CAST(*c)->GetName());
501 LogDebug("[Parent << Object] " << CAST(*c)->GetName()
503 << CAST(*o)->GetName());
506 registerObjects(libObj, children);
512 PluginsInstaller::OptionalPluginMetafileData PluginsInstaller::parseMetafile(
513 const std::string& path) const
515 LogInfo("Plugin Config file::" << path);
518 PluginMetafileData pluginInfo;
519 PluginMetafileReader reader;
520 reader.initialize(path);
521 reader.read(pluginInfo);
523 FOREACH(it, pluginInfo.m_featureContainer) {
524 LogDebug("Parsed feature : " << it->m_name);
526 FOREACH(devCap, it->m_deviceCapabilities) {
527 LogDebug(" | DevCap : " << *devCap);
530 return OptionalPluginMetafileData(pluginInfo);
532 Catch(ValidationCore::ParserSchemaException::Base) {
533 LogError("Error during file processing " << path);
534 ThrowMsg(PluginInstall::Exceptions::XMLFileParsingException,
535 "Parsing metafile failed");
539 std::string PluginsInstaller::getLibraryName(const std::string& dirPath) const
541 std::string pluginPath = dirPath;
542 size_t indexpos = pluginPath.find_last_of('/');
544 if (std::string::npos == indexpos)
550 indexpos += 1; // move after '/'
553 std::string libName = pluginPath.substr(indexpos);
554 libName = WrtDB::GlobalConfig::GetPluginPrefix() + libName
555 + WrtDB::GlobalConfig::GetPluginSuffix();
556 LogDebug("Plugin .so: " << libName);
560 bool PluginsInstaller::registerAndUpdateInstallation(
561 const WrtDB::DbPluginHandle& pluginHandle,
562 const PluginObjectsPtr& libraries)
564 PluginHandleSetPtr handles = PluginHandleSetPtr(new PluginHandleSet);
566 DbPluginHandle handle = INVALID_PLUGIN_HANDLE;
568 //register requiredObjects
569 FOREACH(it, *(libraries->getDependentObjects()))
571 if (libraries->hasObject(*it)) {
572 LogDebug("Dependency from the same library. ignored");
576 handle = PluginDAO::getPluginHandleForImplementedObject(*it);
577 if (handle == INVALID_PLUGIN_HANDLE) {
578 LogError("Library implementing: " << *it << " NOT FOUND");
579 PluginDAO::setPluginInstallationStatus(
581 PluginDAO::INSTALLATION_WAITING);
585 handles->insert(handle);
588 PluginDAO::registerPluginLibrariesDependencies(pluginHandle, handles);
590 PluginDAO::setPluginInstallationStatus(pluginHandle,
591 PluginDAO::INSTALLATION_COMPLETED);
595 bool PluginsInstaller::fillMappingInterfaces(PluginMetafileData& pluginData,
596 const std::string& filename)
598 void *dlHandle = dlopen(filename.c_str(), RTLD_NOW);
599 if (dlHandle == NULL) {
600 LogError("Failed to load plugin: " << filename << ". Reason: " << dlerror());
605 ExportedApi* entryPoint =
606 static_cast<ExportedApi*> (dlsym(dlHandle, GetExportedSymbolName()));
607 if (NULL == entryPoint) {
608 LogError("Error: " << dlerror());
609 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
612 // obtain feature -> dev-cap mapping
613 feature_mapping_interface_t mappingInterface = {NULL, NULL, NULL};
614 entryPoint->GetProvidedFeatures(&mappingInterface);
616 if (!mappingInterface.featGetter || !mappingInterface.release ||
617 !mappingInterface.dcGetter) {
618 LogError("Failed to obtain mapping interface from .so");
619 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
622 feature_mapping_t* devcapMapping = mappingInterface.featGetter();
624 LogDebug("Getting mapping from features to device capabilities");
626 for (size_t i = 0; i < devcapMapping->featuresCount; ++i) {
627 PluginMetafileData::Feature feature;
628 feature.m_name = devcapMapping->features[i].feature_name;
630 LogDebug("Feature: " << feature.m_name);
632 const devcaps_t* dc =
633 mappingInterface.dcGetter(devcapMapping,
634 devcapMapping->features[i].feature_name);
636 LogDebug("device=cap: " << dc);
639 LogDebug("devcaps count: " << dc->devCapsCount);
641 for (size_t j = 0; j < dc->devCapsCount; ++j) {
642 LogDebug("devcap: " << dc->deviceCaps[j]);
643 feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
647 pluginData.m_featureContainer.insert(feature);
650 mappingInterface.release(devcapMapping);
651 } Catch (PluginInstall::Exceptions::PluginsInstallerException)
653 LogError("Exception while feature mapping");
659 if (dlclose(dlHandle) != 0) {
660 LogError("Cannot close plugin handle");
662 LogDebug("Library is unloaded");
667 void PluginsInstaller::registerPluginObjects(const WrtDB::DbPluginHandle& handle,
668 const PluginObjectsPtr libObjects) const
670 //register implemented objects
671 PluginObjects::ObjectsPtr objects =
672 libObjects->getImplementedObject();
674 FOREACH(it, *objects)
676 WrtDB::PluginDAO::registerPluginImplementedObject(*it, handle);
679 //register requiredObjects
680 objects = libObjects->getDependentObjects();
682 FOREACH(it, *objects)
684 if (libObjects->hasObject(*it)) {
685 LogDebug("Dependency from the same library. ignored");
688 WrtDB::PluginDAO::registerPluginRequiredObject(*it, handle);