Initialize Tizen 2.3
[framework/web/wrt-plugins-common.git] / src_wearable / plugins-installer / plugin_installer.cpp
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file    plugin_installer.cpp
18  * @author  Andrzej Surdej(a.surdej@samgsung.com)
19  * @version
20  * @brief
21  */
22
23 #include "plugin_installer.h"
24
25 #include <sys/stat.h>
26 #include <cstdio>
27 #include <dlfcn.h>
28 #include <string>
29
30 #include <vcore/VCore.h>
31 #include <libxml/parser.h>
32
33 #include "plugin_objects.h"
34 #include "plugin_metafile_reader.h"
35 #include "plugin_installer_errors.h"
36
37 #include <Plugin.h>
38 #include <IObject_cast.h>
39 #include <plugin_utils.h>
40 #include <ExportedApi.h>
41
42 #include <wrt-commons/wrt_plugin_export.h>
43
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>
51
52 #include <dpl/singleton_impl.h>
53
54 using namespace WrtDB;
55 using namespace WrtPluginsApi;
56
57 IMPLEMENT_SINGLETON(PluginsInstaller)
58
59 namespace {
60 const std::string DIRECTORY_SEPARATOR = std::string("/");
61 }
62
63 const int PluginsInstaller::INSTALLATION_ERROR = -1;
64
65 PluginsInstaller::PluginsInstaller() :
66     m_initialized(false)
67 {
68     LogDebug("PluginsInstaller created.");
69 }
70 PluginsInstaller::~PluginsInstaller()
71 {
72     LogDebug("PluginsInstaller destroyed.");
73 }
74
75 void PluginsInstaller::checkDatabaseTablesExistance()
76 {
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"))
84     {
85         LogError("Wrong database. Required tables not exist.");
86         deinitialize();
87         Assert(false && "Wrong database. Required tables not exist.");
88     }
89 }
90
91 bool PluginsInstaller::initialize()
92 {
93     LogDebug("Initializing required systems.");
94
95     // Check paths
96     if (!PluginUtils::checkPaths()) {
97         return false;
98     }
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()));
104
105     xmlInitParser();
106     WrtDB::WrtDatabase::attachToThreadRW();
107     ValidationCore::AttachToThreadRW();
108     checkDatabaseTablesExistance();
109     LogDebug("Initialized.");
110     m_initialized = true;
111     return true;
112 }
113
114 void PluginsInstaller::deinitialize()
115 {
116     LogDebug("Shuting systems down.");
117     m_initialized = false;
118     ValidationCore::DetachFromThread();
119     WrtDB::WrtDatabase::detachFromThread();
120     ValidationCore::VCoreDeinit();
121     xmlCleanupParser();
122     LogDebug("Done");
123 }
124
125 PluginsInstaller::ReturnStatus PluginsInstaller::installPlugin(
126     const std::string& libPath)
127 {
128     if (!m_initialized) {
129         LogError("Plugins installer not initialized.");
130         return ReturnStatus::NotInitialized;
131     }
132     LogDebug("Plugin installation started. Checking path: " << libPath);
133
134     if (!PluginUtils::checkPath(libPath)) {
135         return ReturnStatus::WrongPluginPath;
136     }
137
138     LogDebug("Plugin path ok. Searching for config file...");
139
140     std::string metaFileName = libPath + DIRECTORY_SEPARATOR +
141         std::string(WrtDB::GlobalConfig::GetPluginMetafileName());
142     if (PluginUtils::checkFileExistance(metaFileName)) {
143         return installPluginFromMetafile(libPath, metaFileName);
144     }
145
146     PluginMetafileData pluginInfo;
147     pluginInfo.m_libraryName = getLibraryName(libPath);
148
149     LogDebug(
150         "Config file done. Lib name: " << pluginInfo.m_libraryName
151                                        <<
152         ". Searching for installed plugin...");
153
154     if (WrtDB::PluginDAO::isPluginInstalled(pluginInfo.m_libraryName)) {
155         LogDebug("Plugin already installed.");
156         return ReturnStatus::AlreadyInstalled;
157     }
158     LogDebug("Plugin not installed. Loading library file...");
159
160     PluginObjectsPtr libraryObjects;
161     PluginHandle pluginHandle;
162
163     std::string filename = libPath + DIRECTORY_SEPARATOR +
164         pluginInfo.m_libraryName;
165
166     LogDebug("Loading plugin: " << filename);
167
168     Plugin* plugin;
169     Try
170     {
171         plugin = m_registry.GetPlugin(filename);
172     }
173     Catch(DPL::Exception) {
174         LogError("Loading library failed " << filename);
175         return ReturnStatus::LoadingLibraryError;
176     }
177     libraryObjects = PluginObjectsPtr(new PluginObjects());
178
179     LogDebug("#####");
180     LogDebug("##### Plugin: " << filename << " supports new plugin API");
181     LogDebug("#####");
182
183     FOREACH(o, *plugin->GetObjects()) {
184         libraryObjects->addObjects(CAST(*o)->GetParentName(),
185                                    CAST(*o)->GetName());
186
187         LogDebug("[Parent << Object] " << CAST(*o)->GetParentName()
188                                        << " << "
189                                        << CAST(*o)->GetName());
190
191         registerObjects(libraryObjects, plugin->GetObjects());
192     }
193
194     if (!fillMappingInterfaces(pluginInfo, filename)) {
195         m_registry.RemovePlugin(filename, *plugin);
196         return ReturnStatus::LoadingLibraryError;
197     }
198
199     LogDebug("Library loaded. Registering plugin...");
200
201     Try
202     {
203         pluginHandle =
204             PluginDAO::registerPlugin(pluginInfo, libPath);
205
206         LogDebug("Plugin registered. Registering features...");
207
208         FOREACH(it, pluginInfo.m_featureContainer)
209         {
210             LogError("PluginHandle: " << pluginHandle);
211             FeatureDAO::RegisterFeature(*it, pluginHandle);
212         }
213
214         LogDebug("Features registered. Registering objects...");
215
216         registerPluginObjects(pluginHandle, libraryObjects);
217
218         LogDebug("Registration done. Resolving dependencies...");
219
220         //TODO: can it be replaced with resolvePluginDependencies(handle)
221         if (!registerAndUpdateInstallation(pluginHandle, libraryObjects)) {
222             return ReturnStatus::InstallationWaiting;
223         }
224     } Catch(DPL::Exception) {
225         LogError("Failed to make database entry.");
226         return ReturnStatus::DatabaseError;
227     }
228
229     LogDebug("Plugin installed successfully.");
230     return ReturnStatus::Success;
231 }
232
233 PluginObjectsPtr PluginsInstaller::loadLibraryFromMetafile(
234     const std::string& libName) const
235 {
236     LogDebug("Loading library: " << libName);
237
238     void *dlHandle = dlopen(libName.c_str(), RTLD_NOW);
239     if (dlHandle == NULL) {
240         const char* error = (const char*)dlerror();
241         LogError(
242             "Failed to load plugin: " << libName <<
243             ". Reason: " << (error != NULL ? error : "unknown"));
244         ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
245     }
246
247     const js_entity_definition_t *rawEntityList = NULL;
248     get_widget_entity_map_proc *getWidgetEntityMapProcPtr = NULL;
249
250     getWidgetEntityMapProcPtr =
251         reinterpret_cast<get_widget_entity_map_proc *>(dlsym(dlHandle,
252                                                              PLUGIN_GET_CLASS_MAP_PROC_NAME));
253
254     if (getWidgetEntityMapProcPtr) {
255         rawEntityList = (*getWidgetEntityMapProcPtr)();
256     } else {
257         rawEntityList =
258             static_cast<const js_entity_definition_t *>(dlsym(dlHandle,
259                                                               PLUGIN_CLASS_MAP_NAME));
260     }
261
262     if (rawEntityList == NULL) {
263         dlclose(dlHandle);
264         LogError("Failed to read class name" << libName);
265         ThrowMsg(PluginInstall::Exceptions::LibraryException, "Library error");
266     }
267
268     PluginObjectsPtr libraryObjects = PluginObjectsPtr(new PluginObjects());
269     const js_entity_definition_t *rawEntityListIterator = rawEntityList;
270
271     LogDebug("#####");
272     LogDebug("##### Plugin: " << libName << " is using deprecated API");
273     LogDebug("#####");
274
275     while (rawEntityListIterator->parent_name != NULL &&
276            rawEntityListIterator->object_name != NULL)
277     {
278         LogDebug("#####     [" << rawEntityListIterator->object_name << "]: ");
279         LogDebug("#####     Parent: " << rawEntityListIterator->parent_name);
280         LogDebug("#####");
281
282         libraryObjects->addObjects(rawEntityListIterator->parent_name,
283                                    rawEntityListIterator->object_name);
284
285         ++rawEntityListIterator;
286     }
287
288     // Unload library
289     if (dlclose(dlHandle) != 0) {
290         LogError("Cannot close plugin handle");
291     } else {
292         LogDebug("Library is unloaded");
293     }
294
295     // Load export table
296     LogDebug("Library successfuly loaded and parsed");
297
298     return libraryObjects;
299 }
300
301 PluginsInstaller::ReturnStatus PluginsInstaller::installPluginFromMetafile(
302     const std::string& path, const std::string& metaFilePath)
303 {
304     if (!m_initialized) {
305         LogError("Plugins installer not initialized.");
306         return ReturnStatus::NotInitialized;
307     }
308     OptionalPluginMetafileData pluginData;
309     Try
310     {
311         pluginData = parseMetafile(metaFilePath);
312     }
313     Catch(PluginInstall::Exceptions::XMLFileParsingException)
314     {
315         LogError("Parsing metafile failed.");
316         return ReturnStatus::MetafileError;
317     }
318     if (!pluginData) {
319         return ReturnStatus::MetafileError;
320     }
321
322     if (WrtDB::PluginDAO::isPluginInstalled(pluginData->m_libraryName)) {
323         LogDebug("Plugin already installed.");
324         return ReturnStatus::AlreadyInstalled;
325     }
326     Try {
327         LogError(
328             "path is: " << path << ", libraryName: " <<
329             pluginData->m_libraryName);
330         PluginObjectsPtr objects = loadLibraryFromMetafile(
331                 path + DIRECTORY_SEPARATOR + pluginData->m_libraryName);
332
333         PluginHandle pluginHandle =
334             PluginDAO::registerPlugin(*pluginData, path);
335
336         LogDebug("Plugin registered. Registering features...");
337
338         FOREACH(it, pluginData->m_featureContainer)
339         {
340             LogError("PluginHandle: " << pluginHandle);
341             FeatureDAO::RegisterFeature(*it, pluginHandle);
342         }
343
344         LogDebug("Features registered. Registering objects...");
345
346         registerPluginObjects(pluginHandle, objects);
347
348         LogDebug("Objects registered. Finishing...");
349
350         if (!registerAndUpdateInstallation(pluginHandle, objects)) {
351             return ReturnStatus::InstallationWaiting;
352         }
353     } Catch(DPL::Exception) {
354         LogError("Failed to make database entry.");
355         return ReturnStatus::DatabaseError;
356     }
357
358     LogDebug("Plugin installed successfully.");
359     return ReturnStatus::Success;
360 }
361
362 int PluginsInstaller::installAllPlugins()
363 {
364     if (!m_initialized) {
365         LogError("Plugins installer not initialized.");
366         return INSTALLATION_ERROR;
367     }
368     LogDebug("Installing plugins ...");
369
370     std::string PLUGIN_PATH = std::string(GlobalConfig::GetDevicePluginPath());
371
372     DIR *dir;
373     dir = opendir(PLUGIN_PATH.c_str());
374
375     if (!dir) {
376         return INSTALLATION_ERROR;
377     }
378
379     LogDebug("Plugin DIRECTORY IS" << PLUGIN_PATH);
380     int return_code;
381     struct dirent libdir;
382     struct dirent* result;
383
384     errno = 0;
385
386     std::list<std::string> pluginsPaths;
387
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)
393         {
394             continue;
395         }
396
397         std::string path = PLUGIN_PATH;
398         path += "/";
399         path += libdir.d_name;
400
401         struct stat tmp;
402
403         if (stat(path.c_str(), &tmp) == -1) {
404             LogError("Failed to open file" << path);
405             continue;
406         }
407
408         if (!S_ISDIR(tmp.st_mode)) {
409             LogError("Not a directory" << path);
410             continue;
411         }
412
413         LogDebug("Found plugin at " << path);
414         pluginsPaths.push_back(path);
415     }
416
417     if (0 != return_code)
418         LogError("Error while reading directory.");
419
420     if (-1 == closedir(dir)) {
421         LogError("Failed to close dir: " << PLUGIN_PATH);
422     }
423
424     LogDebug("Plugins to install: " << pluginsPaths.size());
425
426     for (size_t k = 0; k <= pluginsPaths.size(); ++k) {
427         printf(" ");
428     }
429     printf("]\r[");
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");
440         } else {
441             LogError("Plugin installation failed");
442         }
443         printf("#");
444         fflush(stdout);
445     }
446     printf("\n");
447     installedPluginsCount += installWaitingPlugins();
448     m_registry.UnloadAll();
449     LogDebug("Installed " << installedPluginsCount
450                          << " plugins of total: " << pluginsPaths.size());
451     return installedPluginsCount;
452 }
453
454 int PluginsInstaller::installWaitingPlugins()
455 {
456     PluginHandleSetPtr waitingPlugins;
457
458     waitingPlugins =
459         PluginDAO::getPluginHandleByStatus(PluginDAO::INSTALLATION_WAITING);
460
461     int pluginsInstalled = 0;
462     FOREACH(it, *waitingPlugins)
463     {
464         if (resolvePluginDependencies(*it)) {
465             ++pluginsInstalled;
466         }
467     }
468     return pluginsInstalled;
469 }
470
471 bool PluginsInstaller::resolvePluginDependencies(PluginHandle handle)
472 {
473     PluginHandleSetPtr dependencies(new PluginHandleSet);
474
475     PluginObjects::ObjectsPtr requiredObjects =
476         PluginDAO::getRequiredObjectsForPluginHandle(handle);
477
478     PluginHandle depHandle = INVALID_PLUGIN_HANDLE;
479
480     FOREACH(requiredObject, *requiredObjects)
481     {
482         depHandle =
483             PluginDAO::getPluginHandleForImplementedObject(*requiredObject);
484
485         if (INVALID_PLUGIN_HANDLE == depHandle) {
486             LogError("Library implementing: " <<
487                      *requiredObject << " NOT FOUND");
488             return false;
489         }
490         dependencies->insert(depHandle);
491     }
492
493     PluginDAO::registerPluginLibrariesDependencies(handle, dependencies);
494     PluginDAO::setPluginInstallationStatus(handle,
495                                            PluginDAO::INSTALLATION_COMPLETED);
496
497     return true;
498 }
499
500 void PluginsInstaller::registerObjects(const PluginObjectsPtr& libObj,
501                                        const IObjectsListPtr& objects) const
502 {
503     LogDebug("registerObjects invoked");
504
505     FOREACH(o, *objects)
506     {
507         auto children = CAST(*o)->GetChildren();
508
509         if (children) {
510             FOREACH(c, *children)
511             {
512                 libObj->addObjects(CAST(*o)->GetName(), CAST(*c)->GetName());
513
514                 LogDebug("[Parent << Object] " << CAST(*c)->GetName()
515                                                << " << "
516                                                << CAST(*o)->GetName());
517             }
518
519             registerObjects(libObj, children);
520         }
521     }
522 }
523
524 PluginsInstaller::OptionalPluginMetafileData PluginsInstaller::parseMetafile(
525     const std::string& path) const
526 {
527     LogDebug("Plugin Config file::" << path);
528     Try
529     {
530         PluginMetafileData pluginInfo;
531         PluginMetafileReader reader;
532         reader.initialize(path);
533         reader.read(pluginInfo);
534
535         FOREACH(it, pluginInfo.m_featureContainer) {
536             LogDebug("Parsed feature : " << it->m_name);
537
538             FOREACH(devCap, it->m_deviceCapabilities) {
539                 LogDebug("  |  DevCap : " << *devCap);
540             }
541         }
542         return OptionalPluginMetafileData(pluginInfo);
543     }
544     Catch(ValidationCore::ParserSchemaException::Base) {
545         LogError("Error during file processing " << path);
546         ThrowMsg(PluginInstall::Exceptions::XMLFileParsingException,
547                  "Parsing metafile failed");
548     }
549 }
550
551 std::string PluginsInstaller::getLibraryName(const std::string& dirPath) const
552 {
553     std::string pluginPath = dirPath;
554     size_t indexpos = pluginPath.find_last_of('/');
555
556     if (std::string::npos == indexpos) {
557         indexpos = 0;
558     } else {
559         indexpos += 1;  // move after '/'
560     }
561
562     std::string libName = pluginPath.substr(indexpos);
563     libName = WrtDB::GlobalConfig::GetPluginPrefix() + libName
564         + WrtDB::GlobalConfig::GetPluginSuffix();
565     LogDebug("Plugin .so: " << libName);
566     return libName;
567 }
568
569 bool PluginsInstaller::registerAndUpdateInstallation(
570     const WrtDB::DbPluginHandle& pluginHandle,
571     const PluginObjectsPtr& libraries)
572 {
573     PluginHandleSetPtr handles = PluginHandleSetPtr(new PluginHandleSet);
574
575     DbPluginHandle handle = INVALID_PLUGIN_HANDLE;
576
577     //register requiredObjects
578     FOREACH(it, *(libraries->getDependentObjects()))
579     {
580         if (libraries->hasObject(*it)) {
581             LogDebug("Dependency from the same library. ignored");
582             continue;
583         }
584
585         handle = PluginDAO::getPluginHandleForImplementedObject(*it);
586         if (handle == INVALID_PLUGIN_HANDLE) {
587             LogError("Library implementing: " << *it << " NOT FOUND");
588             PluginDAO::setPluginInstallationStatus(
589                 pluginHandle,
590                 PluginDAO::INSTALLATION_WAITING);
591             return false;
592         }
593
594         handles->insert(handle);
595     }
596
597     PluginDAO::registerPluginLibrariesDependencies(pluginHandle, handles);
598
599     PluginDAO::setPluginInstallationStatus(pluginHandle,
600                                            PluginDAO::INSTALLATION_COMPLETED);
601     return true;
602 }
603
604 bool PluginsInstaller::fillMappingInterfaces(PluginMetafileData& pluginData,
605                                              const std::string& filename)
606 {
607     void *dlHandle = dlopen(filename.c_str(), RTLD_NOW);
608     if (dlHandle == NULL) {
609         const char* error = (const char*)dlerror();
610         LogError(
611             "Failed to load plugin: " << filename << ". Reason: " << (error != NULL ? error : "unknown"));
612         return false;
613     }
614     Try
615     {
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,
622                      "Library error");
623         }
624
625         // obtain feature -> dev-cap mapping
626         feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
627         entryPoint->GetProvidedFeatures(&mappingInterface);
628
629         if (!mappingInterface.featGetter || !mappingInterface.release ||
630             !mappingInterface.dcGetter)
631         {
632             LogError("Failed to obtain mapping interface from .so");
633             ThrowMsg(PluginInstall::Exceptions::LibraryException,
634                      "Library error");
635         }
636
637         feature_mapping_t* devcapMapping = mappingInterface.featGetter();
638
639         LogDebug("Getting mapping from features to device capabilities");
640
641         for (size_t i = 0; i < devcapMapping->featuresCount; ++i) {
642             PluginMetafileData::Feature feature;
643             feature.m_name = devcapMapping->features[i].feature_name;
644
645             LogDebug("Feature: " << feature.m_name);
646
647             const devcaps_t* dc =
648                 mappingInterface.dcGetter(
649                     devcapMapping,
650                     devcapMapping->features[i].
651                         feature_name);
652
653             LogDebug("device=cap: " << dc);
654
655             if (dc) {
656                 LogDebug("devcaps count: " << dc->devCapsCount);
657
658                 for (size_t j = 0; j < dc->devCapsCount; ++j) {
659                     LogDebug("devcap: " << dc->deviceCaps[j]);
660                     feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
661                 }
662             }
663
664             pluginData.m_featureContainer.insert(feature);
665         }
666
667         mappingInterface.release(devcapMapping);
668     } Catch(PluginInstall::Exceptions::PluginsInstallerException)
669     {
670         LogError("Exception while feature mapping");
671         dlclose(dlHandle);
672         return false;
673     }
674
675     // Unload library
676     if (dlclose(dlHandle) != 0) {
677         LogError("Cannot close plugin handle");
678     } else {
679         LogDebug("Library is unloaded");
680     }
681     return true;
682 }
683
684 void PluginsInstaller::registerPluginObjects(
685     const WrtDB::DbPluginHandle& handle,
686     const PluginObjectsPtr libObjects)
687 const
688 {
689     //register implemented objects
690     PluginObjects::ObjectsPtr objects =
691         libObjects->getImplementedObject();
692
693     FOREACH(it, *objects)
694     {
695         WrtDB::PluginDAO::registerPluginImplementedObject(*it, handle);
696     }
697
698     //register requiredObjects
699     objects = libObjects->getDependentObjects();
700
701     FOREACH(it, *objects)
702     {
703         if (libObjects->hasObject(*it)) {
704             LogDebug("Dependency from the same library. ignored");
705             continue;
706         }
707         WrtDB::PluginDAO::registerPluginRequiredObject(*it, handle);
708     }
709 }
710