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() :
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;
139 LogInfo("Plugin path ok. Searching for config file...");
141 std::string metaFileName = libPath + DIRECTORY_SEPARATOR +
142 std::string(WrtDB::GlobalConfig::GetPluginMetafileName());
143 if (PluginUtils::checkFileExistance(metaFileName)) {
144 return installPluginFromMetafile(libPath, metaFileName);
147 PluginMetafileData pluginInfo;
148 pluginInfo.m_libraryName = getLibraryName(libPath);
151 "Config file done. Lib name: " << pluginInfo.m_libraryName
153 ". Searching for installed plugin...");
155 if (WrtDB::PluginDAO::isPluginInstalled(pluginInfo.m_libraryName)) {
156 LogInfo("Plugin already installed.");
157 return ReturnStatus::AlreadyInstalled;
159 LogInfo("Plugin not installed. Loading library file...");
161 PluginObjectsPtr libraryObjects;
162 PluginHandle pluginHandle;
164 std::string filename = libPath + DIRECTORY_SEPARATOR +
165 pluginInfo.m_libraryName;
167 LogDebug("Loading plugin: " << filename);
172 plugin = m_registry.GetPlugin(filename);
174 Catch(DPL::Exception) {
175 LogError("Loading library failed " << filename);
176 return ReturnStatus::LoadingLibraryError;
178 libraryObjects = PluginObjectsPtr(new PluginObjects());
181 LogInfo("##### Plugin: " << filename << " supports new plugin API");
184 FOREACH(o, *plugin->GetObjects()) {
185 libraryObjects->addObjects(CAST(*o)->GetParentName(),
186 CAST(*o)->GetName());
188 LogDebug("[Parent << Object] " << CAST(*o)->GetParentName()
190 << CAST(*o)->GetName());
192 registerObjects(libraryObjects, plugin->GetObjects());
195 if (!fillMappingInterfaces(pluginInfo, filename)) {
196 m_registry.RemovePlugin(filename, *plugin);
197 return ReturnStatus::LoadingLibraryError;
200 LogInfo("Library loaded. Registering plugin...");
205 PluginDAO::registerPlugin(pluginInfo, libPath);
207 LogInfo("Plugin registered. Registering features...");
209 FOREACH(it, pluginInfo.m_featureContainer)
211 LogError("PluginHandle: " << pluginHandle);
212 FeatureDAO::RegisterFeature(*it, pluginHandle);
215 LogInfo("Features registered. Registering objects...");
217 registerPluginObjects(pluginHandle, libraryObjects);
219 LogInfo("Registration done. Resolving dependencies...");
221 //TODO: can it be replaced with resolvePluginDependencies(handle)
222 if (!registerAndUpdateInstallation(pluginHandle, libraryObjects)) {
223 return ReturnStatus::InstallationWaiting;
225 } Catch(DPL::Exception) {
226 LogError("Failed to make database entry.");
227 return ReturnStatus::DatabaseError;
230 LogInfo("Plugin installed successfully.");
231 return ReturnStatus::Success;
234 PluginObjectsPtr PluginsInstaller::loadLibraryFromMetafile(
235 const std::string& libName) const
237 LogInfo("Loading library: " << libName);
239 void *dlHandle = dlopen(libName.c_str(), RTLD_NOW);
240 if (dlHandle == NULL) {
242 "Failed to load plugin: " << libName <<
243 ". Reason: " << dlerror());
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 LogInfo("##### Plugin: " << libName << " is using deprecated API");
275 while (rawEntityListIterator->parent_name != NULL &&
276 rawEntityListIterator->object_name != NULL)
278 LogInfo("##### [" << rawEntityListIterator->object_name << "]: ");
279 LogInfo("##### 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;
318 if (pluginData.IsNull()) {
319 return ReturnStatus::MetafileError;
322 if (WrtDB::PluginDAO::isPluginInstalled(pluginData->m_libraryName)) {
323 LogInfo("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 LogInfo("Plugin registered. Registering features...");
338 FOREACH(it, pluginData->m_featureContainer)
340 LogError("PluginHandle: " << pluginHandle);
341 FeatureDAO::RegisterFeature(*it, pluginHandle);
344 LogInfo("Features registered. Registering objects...");
346 registerPluginObjects(pluginHandle, objects);
348 LogInfo("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 LogInfo("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 LogInfo("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 == TEMP_FAILURE_RETRY(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 LogInfo("Preparing to plugin installation: " << *it);
434 ret = installPlugin(*it);
435 if (ReturnStatus::Success == ret) {
436 ++installedPluginsCount;
437 LogInfo("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 LogInfo("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 LogInfo("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) {
610 "Failed to load plugin: " << filename << ". Reason: " << dlerror());
615 ExportedApi* entryPoint =
616 static_cast<ExportedApi*>(dlsym(dlHandle, GetExportedSymbolName()));
617 if (NULL == entryPoint) {
618 LogError("Error: " << dlerror());
619 ThrowMsg(PluginInstall::Exceptions::LibraryException,
623 // obtain feature -> dev-cap mapping
624 feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
625 entryPoint->GetProvidedFeatures(&mappingInterface);
627 if (!mappingInterface.featGetter || !mappingInterface.release ||
628 !mappingInterface.dcGetter)
630 LogError("Failed to obtain mapping interface from .so");
631 ThrowMsg(PluginInstall::Exceptions::LibraryException,
635 feature_mapping_t* devcapMapping = mappingInterface.featGetter();
637 LogDebug("Getting mapping from features to device capabilities");
639 for (size_t i = 0; i < devcapMapping->featuresCount; ++i) {
640 PluginMetafileData::Feature feature;
641 feature.m_name = devcapMapping->features[i].feature_name;
643 LogDebug("Feature: " << feature.m_name);
645 const devcaps_t* dc =
646 mappingInterface.dcGetter(
648 devcapMapping->features[i].
651 LogDebug("device=cap: " << dc);
654 LogDebug("devcaps count: " << dc->devCapsCount);
656 for (size_t j = 0; j < dc->devCapsCount; ++j) {
657 LogDebug("devcap: " << dc->deviceCaps[j]);
658 feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
662 pluginData.m_featureContainer.insert(feature);
665 mappingInterface.release(devcapMapping);
666 } Catch(PluginInstall::Exceptions::PluginsInstallerException)
668 LogError("Exception while feature mapping");
674 if (dlclose(dlHandle) != 0) {
675 LogError("Cannot close plugin handle");
677 LogDebug("Library is unloaded");
682 void PluginsInstaller::registerPluginObjects(
683 const WrtDB::DbPluginHandle& handle,
684 const PluginObjectsPtr libObjects)
687 //register implemented objects
688 PluginObjects::ObjectsPtr objects =
689 libObjects->getImplementedObject();
691 FOREACH(it, *objects)
693 WrtDB::PluginDAO::registerPluginImplementedObject(*it, handle);
696 //register requiredObjects
697 objects = libObjects->getDependentObjects();
699 FOREACH(it, *objects)
701 if (libObjects->hasObject(*it)) {
702 LogDebug("Dependency from the same library. ignored");
705 WrtDB::PluginDAO::registerPluginRequiredObject(*it, handle);