57d3c0ccce6b83f3b01dbb632cd649e35a9bc21a
[framework/web/wrt-installer.git] / src / 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 <plugin.h>
39 #include <wrt_common_types.h>
40 #include <dpl/wrt-dao-rw/feature_dao.h>
41 #include <dpl/wrt-dao-rw/plugin_dao.h>
42 #include "plugin_objects.h"
43 #include <wrt_plugin_export.h>
44
45 using namespace WrtDB;
46
47 namespace {
48 const std::string DIRECTORY_SEPARATOR = std::string("/");
49 }
50
51 #define SET_PLUGIN_INSTALL_PROGRESS(step, desc)              \
52     m_context->installerTask->UpdateProgress(               \
53         PluginInstallerContext::step, desc);
54
55 #define DISABLE_IF_PLUGIN_WITHOUT_LIB()        \
56     if(m_pluginInfo.m_libraryName.empty()) \
57     {                                          \
58         LogWarning("Plugin without library."); \
59         return;                                \
60     }
61
62 namespace Jobs {
63 namespace PluginInstall {
64
65 PluginInstallTask::PluginInstallTask(PluginInstallerContext *inCont) :
66     DPL::TaskDecl<PluginInstallTask>(this),
67     m_context(inCont),
68     m_dataFromConfigXML(true)
69 {
70     AddStep(&PluginInstallTask::stepCheckPluginPath);
71     AddStep(&PluginInstallTask::stepParseConfigFile);
72     AddStep(&PluginInstallTask::stepFindPluginLibrary);
73     AddStep(&PluginInstallTask::stepCheckIfAlreadyInstalled);
74     AddStep(&PluginInstallTask::stepLoadPluginLibrary);
75     AddStep(&PluginInstallTask::stepRegisterPlugin);
76     AddStep(&PluginInstallTask::stepRegisterFeatures);
77     AddStep(&PluginInstallTask::stepRegisterPluginObjects);
78     AddStep(&PluginInstallTask::stepResolvePluginDependencies);
79
80     SET_PLUGIN_INSTALL_PROGRESS(START, "Installation initialized");
81 }
82
83 PluginInstallTask::~PluginInstallTask()
84 {
85 }
86
87 void PluginInstallTask::stepCheckPluginPath()
88 {
89     LogInfo("Plugin installation: step CheckPluginPath");
90
91     struct stat tmp;
92
93     if (-1 == stat(m_context->pluginFilePath.c_str(), &tmp)) {
94         ThrowMsg(Exceptions::PluginPathFailed,
95                  "Stat function failed");
96     }
97
98     if (!S_ISDIR(tmp.st_mode)) {
99         ThrowMsg(Exceptions::PluginPathFailed,
100                  "Invalid Directory");
101     }
102
103     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Path to plugin verified");
104 }
105
106 void PluginInstallTask::stepParseConfigFile()
107 {
108     LogInfo("Plugin installation: step parse config file");
109
110     struct stat tmp;
111
112     std::string filename = m_context->pluginFilePath + DIRECTORY_SEPARATOR +
113         std::string(GlobalConfig::GetPluginMetafileName());
114
115     if (-1 == stat(filename.c_str(), &tmp)) {
116         m_dataFromConfigXML = false;
117         return;
118     }
119
120     LogInfo("Plugin Config file::" << filename);
121
122     Try
123     {
124         PluginMetafileReader reader;
125         reader.initialize(filename);
126         reader.read(m_pluginInfo);
127
128         FOREACH(it, m_pluginInfo.m_featureContainer)
129         {
130             LogDebug("Parsed feature : " << it->m_name);
131             FOREACH (devCap, it->m_deviceCapabilities) {
132                 LogDebug("  |  DevCap : " << *devCap);
133             }
134         }
135
136         SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Config file analyzed");
137     }
138     Catch(ValidationCore::ParserSchemaException::Base)
139     {
140         LogError("Error during file processing " << filename);
141         ThrowMsg(Exceptions::PluginMetafileFailed,
142                  "Metafile error");
143     }
144 }
145
146 void PluginInstallTask::stepFindPluginLibrary()
147 {
148     if (m_dataFromConfigXML)
149     {
150         return;
151     }
152     LogDebug("Plugin installation: step find plugin library");
153     std::string pluginPath = m_context->pluginFilePath;
154     size_t indexpos = pluginPath.find_last_of('/');
155
156     if (std::string::npos == indexpos)
157     {
158         indexpos = 0;
159     }
160     else
161     {
162         indexpos += 1;  // move after '/'
163     }
164
165     std::string libName = pluginPath.substr(indexpos);
166     libName = GlobalConfig::GetPluginPrefix() + libName + GlobalConfig::GetPluginSuffix();
167     LogDebug("Plugin .so: " << libName);
168     m_pluginInfo.m_libraryName = libName;
169 }
170
171 void PluginInstallTask::stepCheckIfAlreadyInstalled()
172 {
173     if (PluginDAO::isPluginInstalled(m_pluginInfo.m_libraryName)) {
174         ThrowMsg(Exceptions::PluginAlreadyInstalled,
175                  "Plugin already installed");
176     }
177
178     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_EXISTS_CHECK, "Check if plugin exist");
179 }
180
181 void PluginInstallTask::stepLoadPluginLibrary()
182 {
183     LogInfo("Plugin installation: step load library");
184
185     DISABLE_IF_PLUGIN_WITHOUT_LIB()
186
187     std::string filename = m_context->pluginFilePath + DIRECTORY_SEPARATOR +
188         m_pluginInfo.m_libraryName;
189
190     LogDebug("Loading plugin: " << filename);
191
192     void *dlHandle = dlopen(filename.c_str(), RTLD_NOW);
193     if (dlHandle == NULL ) {
194         LogError(
195                 "Failed to load plugin: " << filename <<
196                 ". Reason: " << dlerror());
197         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
198     }
199
200     const js_entity_definition_t *rawEntityList = NULL;
201     get_widget_entity_map_proc *getWidgetEntityMapProcPtr = NULL;
202
203     getWidgetEntityMapProcPtr =
204         reinterpret_cast<get_widget_entity_map_proc *>(dlsym(dlHandle,
205                     PLUGIN_GET_CLASS_MAP_PROC_NAME));
206
207     if (getWidgetEntityMapProcPtr) {
208         rawEntityList = (*getWidgetEntityMapProcPtr)();
209     } else {
210         rawEntityList =
211             static_cast<const js_entity_definition_t *>(dlsym(dlHandle,
212                         PLUGIN_CLASS_MAP_NAME));
213     }
214
215     if (rawEntityList == NULL) {
216         dlclose(dlHandle);
217         LogError("Failed to read class name" << filename);
218         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
219     }
220
221     if (!m_dataFromConfigXML)
222     {
223         on_widget_init_proc *onWidgetInitProc =
224             reinterpret_cast<on_widget_init_proc *>(
225                 dlsym(dlHandle, PLUGIN_WIDGET_INIT_PROC_NAME));
226
227         if (NULL == onWidgetInitProc)
228         {
229             dlclose(dlHandle);
230             LogError("Failed to read onWidgetInit symbol" << filename);
231             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
232         }
233
234         // obtain feature -> dev-cap mapping
235         feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
236         (*onWidgetInitProc)(&mappingInterface);
237
238         if (!mappingInterface.featGetter || !mappingInterface.release ||
239             !mappingInterface.dcGetter)
240         {
241             LogError("Failed to obtain mapping interface from .so");
242             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
243         }
244
245         feature_mapping_t* devcapMapping = mappingInterface.featGetter();
246
247         LogDebug("Getting mapping from features to device capabilities");
248
249         for (size_t i = 0; i < devcapMapping->featuresCount; ++i)
250         {
251             PluginMetafileData::Feature feature;
252             feature.m_name = devcapMapping->features[i].feature_name;
253
254             LogDebug("Feature: " << feature.m_name);
255
256             const devcaps_t* dc =
257                 mappingInterface.dcGetter(devcapMapping,
258                                           devcapMapping->features[i].feature_name);
259
260             LogDebug("device=cap: " << dc);
261
262             if (dc)
263             {
264                 LogDebug("devcaps count: " << dc->devCapsCount);
265
266                 for (size_t j = 0; j < dc->devCapsCount; ++j)
267                 {
268                     LogDebug("devcap: " << dc->deviceCaps[j]);
269                     feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
270                 }
271             }
272
273             m_pluginInfo.m_featureContainer.insert(feature);
274         }
275
276         mappingInterface.release(devcapMapping);
277     }
278
279     m_libraryObjects = PluginObjectsPtr(new PluginObjects());
280     const js_entity_definition_t *rawEntityListIterator = rawEntityList;
281
282     LogInfo("#####");
283     LogInfo("##### Plugin: " << filename << " supports new plugin API");
284     LogInfo("#####");
285
286     while (rawEntityListIterator->parent_name != NULL &&
287             rawEntityListIterator->object_name != NULL)
288     {
289         LogInfo("#####     [" << rawEntityListIterator->object_name << "]: ");
290         LogInfo("#####     Parent: " << rawEntityListIterator->parent_name);
291         LogInfo("#####");
292
293         m_libraryObjects->addObjects(rawEntityListIterator->parent_name,
294                 rawEntityListIterator->object_name);
295
296         ++rawEntityListIterator;
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 #undef SET_PLUGIN_INSTALL_PROGRESS
418 } //namespace Jobs
419 } //namespace PluginInstall