Update wrt-plugins-common_0.3.60
[platform/framework/web/wrt-plugins-common.git] / src / plugins-installer / jobs / plugin_install / plugin_install_task.cpp
1 /*
2  * Copyright (c) 2011 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    install_one_task.cpp
18  * @author  Pawel Sikorski (p.sikorski@samgsung.com)
19  * @author  Grzegorz Krawczyk (g.krawczyk@samgsung.com)
20  * @version
21  * @brief
22  */
23
24 //SYSTEM INCLUDES
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <dlfcn.h>
28
29 //WRT INCLUDES
30 #include <dpl/log/log.h>
31 #include <dpl/foreach.h>
32 #include <job.h>
33 #include "plugin_install_task.h"
34 #include "job_plugin_install.h"
35 #include "plugin_installer_errors.h"
36 #include "plugin_metafile_reader.h"
37 #include <dpl/wrt-dao-ro/global_config.h>
38 #include <wrt_common_types.h>
39 #include <dpl/wrt-dao-rw/feature_dao.h>
40 #include <dpl/wrt-dao-rw/plugin_dao.h>
41 #include "plugin_objects.h"
42
43 #include <PluginRegistry.h>
44 #include <Plugin.h>
45 #include <IObject_cast.h>
46 #include <SoFeatures.h>
47 #include <ExportedApi.h>
48
49 using namespace WrtDB;
50 using namespace WrtPluginsApi;
51
52 namespace {
53 const std::string DIRECTORY_SEPARATOR = std::string("/");
54 }
55
56 #define SET_PLUGIN_INSTALL_PROGRESS(step, desc)              \
57     m_context->installerTask->UpdateProgress(               \
58         PluginInstallerContext::step, desc);
59
60 #define DISABLE_IF_PLUGIN_WITHOUT_LIB()        \
61     if(m_pluginInfo.m_libraryName.empty()) \
62     {                                          \
63         LogWarning("Plugin without library."); \
64         return;                                \
65     }
66
67 namespace Jobs {
68 namespace PluginInstall {
69
70 PluginInstallTask::PluginInstallTask(PluginInstallerContext *inCont) :
71     DPL::TaskDecl<PluginInstallTask>(this),
72     m_context(inCont),
73     m_dataFromConfigXML(true)
74 {
75     AddStep(&PluginInstallTask::stepCheckPluginPath);
76     AddStep(&PluginInstallTask::stepParseConfigFile);
77     AddStep(&PluginInstallTask::stepFindPluginLibrary);
78     AddStep(&PluginInstallTask::stepCheckIfAlreadyInstalled);
79     AddStep(&PluginInstallTask::stepLoadPluginLibrary);
80     AddStep(&PluginInstallTask::stepRegisterPlugin);
81     AddStep(&PluginInstallTask::stepRegisterFeatures);
82     AddStep(&PluginInstallTask::stepRegisterPluginObjects);
83     AddStep(&PluginInstallTask::stepResolvePluginDependencies);
84
85     SET_PLUGIN_INSTALL_PROGRESS(START, "Installation initialized");
86 }
87
88 PluginInstallTask::~PluginInstallTask()
89 {
90 }
91
92 void PluginInstallTask::stepCheckPluginPath()
93 {
94     LogInfo("Plugin installation: step CheckPluginPath");
95
96     struct stat tmp;
97
98     if (-1 == stat(m_context->pluginFilePath.c_str(), &tmp)) {
99         ThrowMsg(Exceptions::PluginPathFailed,
100                  "Stat function failed");
101     }
102
103     if (!S_ISDIR(tmp.st_mode)) {
104         ThrowMsg(Exceptions::PluginPathFailed,
105                  "Invalid Directory");
106     }
107
108     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Path to plugin verified");
109 }
110
111 void PluginInstallTask::stepParseConfigFile()
112 {
113     LogInfo("Plugin installation: step parse config file");
114
115     struct stat tmp;
116
117     std::string filename = m_context->pluginFilePath + DIRECTORY_SEPARATOR +
118         std::string(GlobalConfig::GetPluginMetafileName());
119
120     if (-1 == stat(filename.c_str(), &tmp)) {
121         m_dataFromConfigXML = false;
122         return;
123     }
124
125     LogInfo("Plugin Config file::" << filename);
126
127     Try
128     {
129         PluginMetafileReader reader;
130         reader.initialize(filename);
131         reader.read(m_pluginInfo);
132
133         FOREACH(it, m_pluginInfo.m_featureContainer)
134         {
135             LogDebug("Parsed feature : " << it->m_name);
136             FOREACH (devCap, it->m_deviceCapabilities) {
137                 LogDebug("  |  DevCap : " << *devCap);
138             }
139         }
140
141         SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Config file analyzed");
142     }
143     Catch(ValidationCore::ParserSchemaException::Base)
144     {
145         LogError("Error during file processing " << filename);
146         ThrowMsg(Exceptions::PluginMetafileFailed,
147                  "Metafile error");
148     }
149 }
150
151 void PluginInstallTask::stepFindPluginLibrary()
152 {
153     if (m_dataFromConfigXML)
154     {
155         return;
156     }
157     LogDebug("Plugin installation: step find plugin library");
158     std::string pluginPath = m_context->pluginFilePath;
159     size_t indexpos = pluginPath.find_last_of('/');
160
161     if (std::string::npos == indexpos)
162     {
163         indexpos = 0;
164     }
165     else
166     {
167         indexpos += 1;  // move after '/'
168     }
169
170     std::string libName = pluginPath.substr(indexpos);
171     libName = GlobalConfig::GetPluginPrefix() + libName + GlobalConfig::GetPluginSuffix();
172     LogDebug("Plugin .so: " << libName);
173     m_pluginInfo.m_libraryName = libName;
174 }
175
176 void PluginInstallTask::stepCheckIfAlreadyInstalled()
177 {
178     if (PluginDAO::isPluginInstalled(m_pluginInfo.m_libraryName)) {
179         ThrowMsg(Exceptions::PluginAlreadyInstalled,
180                  "Plugin already installed");
181     }
182
183     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_EXISTS_CHECK, "Check if plugin exist");
184 }
185
186 void PluginInstallTask::stepLoadPluginLibrary()
187 {
188     LogInfo("Plugin installation: step load library");
189
190     DISABLE_IF_PLUGIN_WITHOUT_LIB()
191
192     std::string filename = m_context->pluginFilePath + DIRECTORY_SEPARATOR +
193         m_pluginInfo.m_libraryName;
194
195     LogDebug("Loading plugin: " << filename);
196
197     void *dlHandle = dlopen(filename.c_str(), RTLD_NOW);
198     if (dlHandle == NULL ) {
199         LogError(
200                 "Failed to load plugin: " << filename <<
201                 ". Reason: " << dlerror());
202         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
203     }
204
205     //TODO move it out
206     PluginRegistry registry;
207
208     Plugin* plugin;
209
210     Try{
211         plugin = registry.GetPlugin(filename);
212     }
213     Catch(DPL::Exception)
214     {
215         LogError("Loading library failed " << filename);
216         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
217     }
218
219     if(!plugin)
220     {
221         LogError("Failed to open library" << filename);
222         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
223     }
224
225     m_libraryObjects = PluginObjectsPtr(new PluginObjects());
226
227     LogInfo("#####");
228     LogInfo("##### Plugin: " << filename << " supports new plugin API");
229     LogInfo("#####");
230
231     FOREACH(o, *plugin->GetObjects())
232     {
233        m_libraryObjects->addObjects(CAST(*o)->GetParentName(),
234                                     CAST(*o)->GetName());
235
236        LogDebug("[Parent << Object] " << CAST(*o)->GetParentName()
237                                     << " << "
238                                     << CAST(*o)->GetName());
239
240        registerObjects(plugin->GetObjects());
241     }
242
243
244     if (!m_dataFromConfigXML)
245     {
246         ExportedApi* entryPoint =
247             static_cast<ExportedApi*>(dlsym(dlHandle, GetExportedSymbolName()));
248         if (NULL == entryPoint)
249         {
250             LogError("Error: " << dlerror());
251             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
252         }
253
254         // obtain feature -> dev-cap mapping
255         feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
256         entryPoint->GetProvidedFeatures(&mappingInterface);
257
258         if (!mappingInterface.featGetter || !mappingInterface.release ||
259             !mappingInterface.dcGetter)
260         {
261             LogError("Failed to obtain mapping interface from .so");
262             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
263         }
264
265         feature_mapping_t* devcapMapping = mappingInterface.featGetter();
266
267         LogDebug("Getting mapping from features to device capabilities");
268
269         for (size_t i = 0; i < devcapMapping->featuresCount; ++i)
270         {
271             PluginMetafileData::Feature feature;
272             feature.m_name = devcapMapping->features[i].feature_name;
273
274             LogDebug("Feature: " << feature.m_name);
275
276             const devcaps_t* dc =
277                 mappingInterface.dcGetter(devcapMapping,
278                                           devcapMapping->features[i].feature_name);
279
280             LogDebug("device=cap: " << dc);
281
282             if (dc)
283             {
284                 LogDebug("devcaps count: " << dc->devCapsCount);
285
286                 for (size_t j = 0; j < dc->devCapsCount; ++j)
287                 {
288                     LogDebug("devcap: " << dc->deviceCaps[j]);
289                     feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
290                 }
291             }
292
293             m_pluginInfo.m_featureContainer.insert(feature);
294         }
295
296         mappingInterface.release(devcapMapping);
297     }
298
299     // Unload library
300     if (dlclose(dlHandle) != 0) {
301         LogError("Cannot close plugin handle");
302     } else {
303         LogDebug("Library is unloaded");
304     }
305
306     // Load export table
307     LogDebug("Library successfuly loaded and parsed");
308
309     SET_PLUGIN_INSTALL_PROGRESS(LOADING_LIBRARY, "Library loaded and analyzed");
310 }
311
312 void PluginInstallTask::stepRegisterPlugin()
313 {
314     LogInfo("Plugin installation: step register Plugin");
315
316     m_pluginHandle =
317         PluginDAO::registerPlugin(m_pluginInfo, m_context->pluginFilePath);
318
319     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_PLUGIN, "Plugin registered");
320 }
321
322 void PluginInstallTask::stepRegisterFeatures()
323 {
324     LogInfo("Plugin installation: step register features");
325
326     FOREACH(it, m_pluginInfo.m_featureContainer)
327     {
328         LogError("PluginHandle: " << m_pluginHandle);
329         FeatureDAO::RegisterFeature(*it, m_pluginHandle);
330     }
331     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_FEATURES, "Features registered");
332 }
333
334 void PluginInstallTask::stepRegisterPluginObjects()
335 {
336     LogInfo("Plugin installation: step register objects");
337
338     DISABLE_IF_PLUGIN_WITHOUT_LIB()
339
340     //register implemented objects
341     PluginObjects::ObjectsPtr objects =
342         m_libraryObjects->getImplementedObject();
343
344     FOREACH(it, *objects)
345     {
346         PluginDAO::registerPluginImplementedObject(*it, m_pluginHandle);
347     }
348
349     //register requiredObjects
350     objects = m_libraryObjects->getDependentObjects();
351
352     FOREACH(it, *objects)
353     {
354         if (m_libraryObjects->hasObject(*it)) {
355             LogDebug("Dependency from the same library. ignored");
356             continue;
357         }
358
359         PluginDAO::registerPluginRequiredObject(*it, m_pluginHandle);
360     }
361
362     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_OBJECTS, "Plugin Objects registered");
363 }
364
365 void PluginInstallTask::stepResolvePluginDependencies()
366 {
367     LogInfo("Plugin installation: step resolve dependencies ");
368
369     //DISABLE_IF_PLUGIN_WITHOUT_LIB
370     if(m_pluginInfo.m_libraryName.empty())
371     {
372         PluginDAO::setPluginInstallationStatus(m_pluginHandle,
373                                            PluginDAO::INSTALLATION_COMPLETED);
374         //Installation completed
375         m_context->pluginHandle = m_pluginHandle;
376         m_context->installationCompleted = true;
377         LogWarning("Plugin without library.");
378         return;
379     }
380
381     PluginHandleSetPtr handles = PluginHandleSetPtr(new PluginHandleSet);
382
383     DbPluginHandle handle = INVALID_PLUGIN_HANDLE;
384
385     //register requiredObjects
386     FOREACH(it, *(m_libraryObjects->getDependentObjects()))
387     {
388         if (m_libraryObjects->hasObject(*it)) {
389             LogDebug("Dependency from the same library. ignored");
390             continue;
391         }
392
393         handle = PluginDAO::getPluginHandleForImplementedObject(*it);
394         if (handle == INVALID_PLUGIN_HANDLE) {
395             LogError("Library implementing: " << *it << " NOT FOUND");
396             PluginDAO::setPluginInstallationStatus(
397                 m_pluginHandle,
398                 PluginDAO::INSTALLATION_WAITING);
399             return;
400         }
401
402         handles->insert(handle);
403     }
404
405     PluginDAO::registerPluginLibrariesDependencies(m_pluginHandle, handles);
406
407     PluginDAO::setPluginInstallationStatus(m_pluginHandle,
408                                            PluginDAO::INSTALLATION_COMPLETED);
409
410     //Installation completed
411     m_context->pluginHandle = m_pluginHandle;
412     m_context->installationCompleted = true;
413
414     SET_PLUGIN_INSTALL_PROGRESS(RESOLVE_DEPENDENCIES, "Dependencies resolved");
415 }
416
417 void PluginInstallTask::registerObjects(const IObjectsListPtr& objects)
418 {
419    LogDebug("registerObjects invoked");
420
421    FOREACH(o, *objects)
422    {
423        auto children = CAST(*o)->GetChildren();
424
425        if(children)
426        {
427            FOREACH(c, *children)
428            {
429                m_libraryObjects->addObjects(CAST(*o)->GetName(),
430                                             CAST(*c)->GetName());
431
432                LogDebug("[Parent << Object] " << CAST(*c)->GetName()
433                         << " << "
434                         << CAST(*o)->GetName());
435            }
436
437            registerObjects(children);
438        }
439    }
440 }
441
442 #undef SET_PLUGIN_INSTALL_PROGRESS
443 } //namespace Jobs
444 } //namespace PluginInstall