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 LogDebug("PluginsInstaller created.");
71 PluginsInstaller::~PluginsInstaller()
73 LogDebug("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 LogDebug("Plugin installation started. Checking path: " << libPath);
135 if (!PluginUtils::checkPath(libPath)) {
136 return ReturnStatus::WrongPluginPath;
139 LogDebug("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 LogDebug("Plugin already installed.");
157 return ReturnStatus::AlreadyInstalled;
159 LogDebug("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 LogDebug("##### 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 LogDebug("Library loaded. Registering plugin...");
205 PluginDAO::registerPlugin(pluginInfo, libPath);
207 LogDebug("Plugin registered. Registering features...");
209 FOREACH(it, pluginInfo.m_featureContainer)
211 LogError("PluginHandle: " << pluginHandle);
212 FeatureDAO::RegisterFeature(*it, pluginHandle);
215 LogDebug("Features registered. Registering objects...");
217 registerPluginObjects(pluginHandle, libraryObjects);
219 LogDebug("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 LogDebug("Plugin installed successfully.");
231 return ReturnStatus::Success;
234 PluginObjectsPtr PluginsInstaller::loadLibraryFromMetafile(
235 const std::string& libName) const
237 LogDebug("Loading library: " << libName);
239 void *dlHandle = dlopen(libName.c_str(), RTLD_NOW);
240 if (dlHandle == NULL) {
241 const char* error = (const char*)dlerror();
243 "Failed to load plugin: " << libName <<
244 ". Reason: " << (error != NULL ? error : "unknown"));
245 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
248 const js_entity_definition_t *rawEntityList = NULL;
249 get_widget_entity_map_proc *getWidgetEntityMapProcPtr = NULL;
251 getWidgetEntityMapProcPtr =
252 reinterpret_cast<get_widget_entity_map_proc *>(dlsym(dlHandle,
253 PLUGIN_GET_CLASS_MAP_PROC_NAME));
255 if (getWidgetEntityMapProcPtr) {
256 rawEntityList = (*getWidgetEntityMapProcPtr)();
259 static_cast<const js_entity_definition_t *>(dlsym(dlHandle,
260 PLUGIN_CLASS_MAP_NAME));
263 if (rawEntityList == NULL) {
265 LogError("Failed to read class name" << libName);
266 ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
269 PluginObjectsPtr libraryObjects = PluginObjectsPtr(new PluginObjects());
270 const js_entity_definition_t *rawEntityListIterator = rawEntityList;
273 LogDebug("##### Plugin: " << libName << " is using deprecated API");
276 while (rawEntityListIterator->parent_name != NULL &&
277 rawEntityListIterator->object_name != NULL)
279 LogDebug("##### [" << rawEntityListIterator->object_name << "]: ");
280 LogDebug("##### Parent: " << rawEntityListIterator->parent_name);
283 libraryObjects->addObjects(rawEntityListIterator->parent_name,
284 rawEntityListIterator->object_name);
286 ++rawEntityListIterator;
290 if (dlclose(dlHandle) != 0) {
291 LogError("Cannot close plugin handle");
293 LogDebug("Library is unloaded");
297 LogDebug("Library successfuly loaded and parsed");
299 return libraryObjects;
302 PluginsInstaller::ReturnStatus PluginsInstaller::installPluginFromMetafile(
303 const std::string& path, const std::string& metaFilePath)
305 if (!m_initialized) {
306 LogError("Plugins installer not initialized.");
307 return ReturnStatus::NotInitialized;
309 OptionalPluginMetafileData pluginData;
312 pluginData = parseMetafile(metaFilePath);
314 Catch(PluginInstall::Exceptions::XMLFileParsingException)
316 LogError("Parsing metafile failed.");
317 return ReturnStatus::MetafileError;
319 if (pluginData.IsNull()) {
320 return ReturnStatus::MetafileError;
323 if (WrtDB::PluginDAO::isPluginInstalled(pluginData->m_libraryName)) {
324 LogDebug("Plugin already installed.");
325 return ReturnStatus::AlreadyInstalled;
329 "path is: " << path << ", libraryName: " <<
330 pluginData->m_libraryName);
331 PluginObjectsPtr objects = loadLibraryFromMetafile(
332 path + DIRECTORY_SEPARATOR + pluginData->m_libraryName);
334 PluginHandle pluginHandle =
335 PluginDAO::registerPlugin(*pluginData, path);
337 LogDebug("Plugin registered. Registering features...");
339 FOREACH(it, pluginData->m_featureContainer)
341 LogError("PluginHandle: " << pluginHandle);
342 FeatureDAO::RegisterFeature(*it, pluginHandle);
345 LogDebug("Features registered. Registering objects...");
347 registerPluginObjects(pluginHandle, objects);
349 LogDebug("Objects registered. Finishing...");
351 if (!registerAndUpdateInstallation(pluginHandle, objects)) {
352 return ReturnStatus::InstallationWaiting;
354 } Catch(DPL::Exception) {
355 LogError("Failed to make database entry.");
356 return ReturnStatus::DatabaseError;
359 LogDebug("Plugin installed successfully.");
360 return ReturnStatus::Success;
363 int PluginsInstaller::installAllPlugins()
365 if (!m_initialized) {
366 LogError("Plugins installer not initialized.");
367 return INSTALLATION_ERROR;
369 LogDebug("Installing plugins ...");
371 std::string PLUGIN_PATH = std::string(GlobalConfig::GetDevicePluginPath());
374 dir = opendir(PLUGIN_PATH.c_str());
377 return INSTALLATION_ERROR;
380 LogDebug("Plugin DIRECTORY IS" << PLUGIN_PATH);
382 struct dirent libdir;
383 struct dirent* result;
387 std::list<std::string> pluginsPaths;
389 for (return_code = readdir_r(dir, &libdir, &result);
390 result != NULL && return_code == 0;
391 return_code = readdir_r(dir, &libdir, &result)) {
392 if (strcmp(libdir.d_name, ".") == 0 ||
393 strcmp(libdir.d_name, "..") == 0)
398 std::string path = PLUGIN_PATH;
400 path += libdir.d_name;
404 if (stat(path.c_str(), &tmp) == -1) {
405 LogError("Failed to open file" << path);
409 if (!S_ISDIR(tmp.st_mode)) {
410 LogError("Not a directory" << path);
414 LogDebug("Found plugin at " << path);
415 pluginsPaths.push_back(path);
418 if (0 != return_code)
419 LogError("Error while reading directory.");
421 if (-1 == TEMP_FAILURE_RETRY(closedir(dir))) {
422 LogError("Failed to close dir: " << PLUGIN_PATH);
425 LogDebug("Plugins to install: " << pluginsPaths.size());
427 for (size_t k = 0; k <= pluginsPaths.size(); ++k) {
431 int installedPluginsCount = 0;
432 ReturnStatus ret = ReturnStatus::Unknown;
433 FOREACH(it, pluginsPaths) {
434 LogDebug("Preparing to plugin installation: " << *it);
435 ret = installPlugin(*it);
436 if (ReturnStatus::Success == ret) {
437 ++installedPluginsCount;
438 LogDebug("Plugin " << *it << " installed.");
439 } else if (ReturnStatus::InstallationWaiting == ret) {
440 LogWarning("Plugin not installed. Waiting for dependency");
442 LogError("Plugin installation failed");
448 installedPluginsCount += installWaitingPlugins();
449 m_registry.UnloadAll();
450 LogDebug("Installed " << installedPluginsCount
451 << " plugins of total: " << pluginsPaths.size());
452 return installedPluginsCount;
455 int PluginsInstaller::installWaitingPlugins()
457 PluginHandleSetPtr waitingPlugins;
460 PluginDAO::getPluginHandleByStatus(PluginDAO::INSTALLATION_WAITING);
462 int pluginsInstalled = 0;
463 FOREACH(it, *waitingPlugins)
465 if (resolvePluginDependencies(*it)) {
469 return pluginsInstalled;
472 bool PluginsInstaller::resolvePluginDependencies(PluginHandle handle)
474 PluginHandleSetPtr dependencies(new PluginHandleSet);
476 PluginObjects::ObjectsPtr requiredObjects =
477 PluginDAO::getRequiredObjectsForPluginHandle(handle);
479 PluginHandle depHandle = INVALID_PLUGIN_HANDLE;
481 FOREACH(requiredObject, *requiredObjects)
484 PluginDAO::getPluginHandleForImplementedObject(*requiredObject);
486 if (INVALID_PLUGIN_HANDLE == depHandle) {
487 LogError("Library implementing: " <<
488 *requiredObject << " NOT FOUND");
491 dependencies->insert(depHandle);
494 PluginDAO::registerPluginLibrariesDependencies(handle, dependencies);
495 PluginDAO::setPluginInstallationStatus(handle,
496 PluginDAO::INSTALLATION_COMPLETED);
501 void PluginsInstaller::registerObjects(const PluginObjectsPtr& libObj,
502 const IObjectsListPtr& objects) const
504 LogDebug("registerObjects invoked");
508 auto children = CAST(*o)->GetChildren();
511 FOREACH(c, *children)
513 libObj->addObjects(CAST(*o)->GetName(), CAST(*c)->GetName());
515 LogDebug("[Parent << Object] " << CAST(*c)->GetName()
517 << CAST(*o)->GetName());
520 registerObjects(libObj, children);
525 PluginsInstaller::OptionalPluginMetafileData PluginsInstaller::parseMetafile(
526 const std::string& path) const
528 LogDebug("Plugin Config file::" << path);
531 PluginMetafileData pluginInfo;
532 PluginMetafileReader reader;
533 reader.initialize(path);
534 reader.read(pluginInfo);
536 FOREACH(it, pluginInfo.m_featureContainer) {
537 LogDebug("Parsed feature : " << it->m_name);
539 FOREACH(devCap, it->m_deviceCapabilities) {
540 LogDebug(" | DevCap : " << *devCap);
543 return OptionalPluginMetafileData(pluginInfo);
545 Catch(ValidationCore::ParserSchemaException::Base) {
546 LogError("Error during file processing " << path);
547 ThrowMsg(PluginInstall::Exceptions::XMLFileParsingException,
548 "Parsing metafile failed");
552 std::string PluginsInstaller::getLibraryName(const std::string& dirPath) const
554 std::string pluginPath = dirPath;
555 size_t indexpos = pluginPath.find_last_of('/');
557 if (std::string::npos == indexpos) {
560 indexpos += 1; // move after '/'
563 std::string libName = pluginPath.substr(indexpos);
564 libName = WrtDB::GlobalConfig::GetPluginPrefix() + libName
565 + WrtDB::GlobalConfig::GetPluginSuffix();
566 LogDebug("Plugin .so: " << libName);
570 bool PluginsInstaller::registerAndUpdateInstallation(
571 const WrtDB::DbPluginHandle& pluginHandle,
572 const PluginObjectsPtr& libraries)
574 PluginHandleSetPtr handles = PluginHandleSetPtr(new PluginHandleSet);
576 DbPluginHandle handle = INVALID_PLUGIN_HANDLE;
578 //register requiredObjects
579 FOREACH(it, *(libraries->getDependentObjects()))
581 if (libraries->hasObject(*it)) {
582 LogDebug("Dependency from the same library. ignored");
586 handle = PluginDAO::getPluginHandleForImplementedObject(*it);
587 if (handle == INVALID_PLUGIN_HANDLE) {
588 LogError("Library implementing: " << *it << " NOT FOUND");
589 PluginDAO::setPluginInstallationStatus(
591 PluginDAO::INSTALLATION_WAITING);
595 handles->insert(handle);
598 PluginDAO::registerPluginLibrariesDependencies(pluginHandle, handles);
600 PluginDAO::setPluginInstallationStatus(pluginHandle,
601 PluginDAO::INSTALLATION_COMPLETED);
605 bool PluginsInstaller::fillMappingInterfaces(PluginMetafileData& pluginData,
606 const std::string& filename)
608 void *dlHandle = dlopen(filename.c_str(), RTLD_NOW);
609 if (dlHandle == NULL) {
610 const char* error = (const char*)dlerror();
612 "Failed to load plugin: " << filename << ". Reason: " << (error != NULL ? error : "unknown"));
617 ExportedApi* entryPoint =
618 static_cast<ExportedApi*>(dlsym(dlHandle, GetExportedSymbolName()));
619 if (NULL == entryPoint) {
620 const char* error = (const char*)dlerror();
621 LogError("Error: " << (error != NULL ? error : "unknown"));
622 ThrowMsg(PluginInstall::Exceptions::LibraryException,
626 // obtain feature -> dev-cap mapping
627 feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
628 entryPoint->GetProvidedFeatures(&mappingInterface);
630 if (!mappingInterface.featGetter || !mappingInterface.release ||
631 !mappingInterface.dcGetter)
633 LogError("Failed to obtain mapping interface from .so");
634 ThrowMsg(PluginInstall::Exceptions::LibraryException,
638 feature_mapping_t* devcapMapping = mappingInterface.featGetter();
640 LogDebug("Getting mapping from features to device capabilities");
642 for (size_t i = 0; i < devcapMapping->featuresCount; ++i) {
643 PluginMetafileData::Feature feature;
644 feature.m_name = devcapMapping->features[i].feature_name;
646 LogDebug("Feature: " << feature.m_name);
648 const devcaps_t* dc =
649 mappingInterface.dcGetter(
651 devcapMapping->features[i].
654 LogDebug("device=cap: " << dc);
657 LogDebug("devcaps count: " << dc->devCapsCount);
659 for (size_t j = 0; j < dc->devCapsCount; ++j) {
660 LogDebug("devcap: " << dc->deviceCaps[j]);
661 feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
665 pluginData.m_featureContainer.insert(feature);
668 mappingInterface.release(devcapMapping);
669 } Catch(PluginInstall::Exceptions::PluginsInstallerException)
671 LogError("Exception while feature mapping");
677 if (dlclose(dlHandle) != 0) {
678 LogError("Cannot close plugin handle");
680 LogDebug("Library is unloaded");
685 void PluginsInstaller::registerPluginObjects(
686 const WrtDB::DbPluginHandle& handle,
687 const PluginObjectsPtr libObjects)
690 //register implemented objects
691 PluginObjects::ObjectsPtr objects =
692 libObjects->getImplementedObject();
694 FOREACH(it, *objects)
696 WrtDB::PluginDAO::registerPluginImplementedObject(*it, handle);
699 //register requiredObjects
700 objects = libObjects->getDependentObjects();
702 FOREACH(it, *objects)
704 if (libObjects->hasObject(*it)) {
705 LogDebug("Dependency from the same library. ignored");
708 WrtDB::PluginDAO::registerPluginRequiredObject(*it, handle);