Merge "Fixing issues found by prevent2 (49866)"
[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 PluginInstallTask::PluginInstallTask(PluginInstallerContext *inCont) :
65     DPL::TaskDecl<PluginInstallTask>(this),
66     m_context(inCont),
67     m_pluginHandle(0),
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 void PluginInstallTask::stepCheckPluginPath()
87 {
88     LogInfo("Plugin installation: step CheckPluginPath");
89
90     struct stat tmp;
91
92     if (-1 == stat(m_context->pluginFilePath.c_str(), &tmp)) {
93         ThrowMsg(Exceptions::PluginPathFailed,
94                  "Stat function failed");
95     }
96
97     if (!S_ISDIR(tmp.st_mode)) {
98         ThrowMsg(Exceptions::PluginPathFailed,
99                  "Invalid Directory");
100     }
101
102     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Path to plugin verified");
103 }
104
105 void PluginInstallTask::stepParseConfigFile()
106 {
107     LogInfo("Plugin installation: step parse config file");
108
109     struct stat tmp;
110
111     std::string filename = m_context->pluginFilePath + DIRECTORY_SEPARATOR +
112         std::string(GlobalConfig::GetPluginMetafileName());
113
114     if (-1 == stat(filename.c_str(), &tmp)) {
115         m_dataFromConfigXML = false;
116         return;
117     }
118
119     LogInfo("Plugin Config file::" << filename);
120
121     Try
122     {
123         PluginMetafileReader reader;
124         reader.initialize(filename);
125         reader.read(m_pluginInfo);
126
127         FOREACH(it, m_pluginInfo.m_featureContainer)
128         {
129             LogDebug("Parsed feature : " << it->m_name);
130             FOREACH(devCap, it->m_deviceCapabilities) {
131                 LogDebug("  |  DevCap : " << *devCap);
132             }
133         }
134
135         SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Config file analyzed");
136     }
137     Catch(ValidationCore::ParserSchemaException::Base)
138     {
139         LogError("Error during file processing " << filename);
140         ThrowMsg(Exceptions::PluginMetafileFailed,
141                  "Metafile error");
142     }
143 }
144
145 void PluginInstallTask::stepFindPluginLibrary()
146 {
147     if (m_dataFromConfigXML) {
148         return;
149     }
150     LogDebug("Plugin installation: step find plugin library");
151     std::string pluginPath = m_context->pluginFilePath;
152     size_t indexpos = pluginPath.find_last_of('/');
153
154     if (std::string::npos == indexpos) {
155         indexpos = 0;
156     } else {
157         indexpos += 1;  // move after '/'
158     }
159
160     std::string libName = pluginPath.substr(indexpos);
161     libName = GlobalConfig::GetPluginPrefix() + libName +
162         GlobalConfig::GetPluginSuffix();
163     LogDebug("Plugin .so: " << libName);
164     m_pluginInfo.m_libraryName = libName;
165 }
166
167 void PluginInstallTask::stepCheckIfAlreadyInstalled()
168 {
169     if (PluginDAO::isPluginInstalled(m_pluginInfo.m_libraryName)) {
170         ThrowMsg(Exceptions::PluginAlreadyInstalled,
171                  "Plugin already installed");
172     }
173
174     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_EXISTS_CHECK, "Check if plugin exist");
175 }
176
177 void PluginInstallTask::stepLoadPluginLibrary()
178 {
179     LogInfo("Plugin installation: step load library");
180
181     DISABLE_IF_PLUGIN_WITHOUT_LIB()
182
183     std::string filename = m_context->pluginFilePath + DIRECTORY_SEPARATOR +
184         m_pluginInfo.m_libraryName;
185
186     LogDebug("Loading plugin: " << filename);
187
188     void *dlHandle = dlopen(filename.c_str(), RTLD_LAZY);
189     if (dlHandle == NULL) {
190         const char* error = (const char*)dlerror();
191         LogError(
192             "Failed to load plugin: " << filename <<
193             ". Reason: " << (error != NULL ? error : "unknown"));
194         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
195     }
196
197     const js_entity_definition_t *rawEntityList = NULL;
198     get_widget_entity_map_proc *getWidgetEntityMapProcPtr = NULL;
199
200     getWidgetEntityMapProcPtr =
201         reinterpret_cast<get_widget_entity_map_proc *>(dlsym(dlHandle,
202                                                              PLUGIN_GET_CLASS_MAP_PROC_NAME));
203
204     if (getWidgetEntityMapProcPtr) {
205         rawEntityList = (*getWidgetEntityMapProcPtr)();
206     } else {
207         rawEntityList =
208             static_cast<const js_entity_definition_t *>(dlsym(dlHandle,
209                                                               PLUGIN_CLASS_MAP_NAME));
210     }
211
212     if (rawEntityList == NULL) {
213         dlclose(dlHandle);
214         LogError("Failed to read class name" << filename);
215         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
216     }
217
218     if (!m_dataFromConfigXML) {
219         on_widget_init_proc *onWidgetInitProc =
220             reinterpret_cast<on_widget_init_proc *>(
221                 dlsym(dlHandle, PLUGIN_WIDGET_INIT_PROC_NAME));
222
223         if (NULL == onWidgetInitProc) {
224             dlclose(dlHandle);
225             LogError("Failed to read onWidgetInit symbol" << filename);
226             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
227         }
228
229         // obtain feature -> dev-cap mapping
230         feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
231         (*onWidgetInitProc)(&mappingInterface);
232
233         if (!mappingInterface.featGetter || !mappingInterface.release ||
234             !mappingInterface.dcGetter)
235         {
236             LogError("Failed to obtain mapping interface from .so");
237             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
238         }
239
240         feature_mapping_t* devcapMapping = mappingInterface.featGetter();
241
242         LogDebug("Getting mapping from features to device capabilities");
243
244         for (size_t i = 0; i < devcapMapping->featuresCount; ++i) {
245             PluginMetafileData::Feature feature;
246             feature.m_name = devcapMapping->features[i].feature_name;
247
248             LogDebug("Feature: " << feature.m_name);
249
250             const devcaps_t* dc =
251                 mappingInterface.dcGetter(
252                     devcapMapping,
253                     devcapMapping->features[i].
254                         feature_name);
255
256             LogDebug("device=cap: " << dc);
257
258             if (dc) {
259                 LogDebug("devcaps count: " << dc->devCapsCount);
260
261                 for (size_t j = 0; j < dc->devCapsCount; ++j) {
262                     LogDebug("devcap: " << dc->deviceCaps[j]);
263                     feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
264                 }
265             }
266
267             m_pluginInfo.m_featureContainer.insert(feature);
268         }
269
270         mappingInterface.release(devcapMapping);
271     }
272
273     m_libraryObjects = PluginObjectsPtr(new PluginObjects());
274     const js_entity_definition_t *rawEntityListIterator = rawEntityList;
275
276     LogInfo("#####");
277     LogInfo("##### Plugin: " << filename << " supports new plugin API");
278     LogInfo("#####");
279
280     while (rawEntityListIterator->parent_name != NULL &&
281            rawEntityListIterator->object_name != NULL)
282     {
283         LogInfo("#####     [" << rawEntityListIterator->object_name << "]: ");
284         LogInfo("#####     Parent: " << rawEntityListIterator->parent_name);
285         LogInfo("#####");
286
287         m_libraryObjects->addObjects(rawEntityListIterator->parent_name,
288                                      rawEntityListIterator->object_name);
289
290         ++rawEntityListIterator;
291     }
292
293     // Unload library
294     if (dlclose(dlHandle) != 0) {
295         LogError("Cannot close plugin handle");
296     } else {
297         LogDebug("Library is unloaded");
298     }
299
300     // Load export table
301     LogDebug("Library successfuly loaded and parsed");
302
303     SET_PLUGIN_INSTALL_PROGRESS(LOADING_LIBRARY, "Library loaded and analyzed");
304 }
305
306 void PluginInstallTask::stepRegisterPlugin()
307 {
308     LogInfo("Plugin installation: step register Plugin");
309
310     m_pluginHandle =
311         PluginDAO::registerPlugin(m_pluginInfo, m_context->pluginFilePath);
312
313     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_PLUGIN, "Plugin registered");
314 }
315
316 void PluginInstallTask::stepRegisterFeatures()
317 {
318     LogInfo("Plugin installation: step register features");
319
320     FOREACH(it, m_pluginInfo.m_featureContainer)
321     {
322         LogError("PluginHandle: " << m_pluginHandle);
323         FeatureDAO::RegisterFeature(*it, m_pluginHandle);
324     }
325     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_FEATURES, "Features registered");
326 }
327
328 void PluginInstallTask::stepRegisterPluginObjects()
329 {
330     LogInfo("Plugin installation: step register objects");
331
332     DISABLE_IF_PLUGIN_WITHOUT_LIB()
333
334     //register implemented objects
335     PluginObjects::ObjectsPtr objects =
336         m_libraryObjects->getImplementedObject();
337
338     FOREACH(it, *objects)
339     {
340         PluginDAO::registerPluginImplementedObject(*it, m_pluginHandle);
341     }
342
343     //register requiredObjects
344     objects = m_libraryObjects->getDependentObjects();
345
346     FOREACH(it, *objects)
347     {
348         if (m_libraryObjects->hasObject(*it)) {
349             LogDebug("Dependency from the same library. ignored");
350             continue;
351         }
352
353         PluginDAO::registerPluginRequiredObject(*it, m_pluginHandle);
354     }
355
356     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_OBJECTS, "Plugin Objects registered");
357 }
358
359 void PluginInstallTask::stepResolvePluginDependencies()
360 {
361     LogInfo("Plugin installation: step resolve dependencies ");
362
363     //DISABLE_IF_PLUGIN_WITHOUT_LIB
364     if (m_pluginInfo.m_libraryName.empty()) {
365         PluginDAO::setPluginInstallationStatus(
366             m_pluginHandle,
367             PluginDAO::
368                 INSTALLATION_COMPLETED);
369         //Installation completed
370         m_context->pluginHandle = m_pluginHandle;
371         m_context->installationCompleted = true;
372         LogWarning("Plugin without library.");
373         return;
374     }
375
376     PluginHandleSetPtr handles = PluginHandleSetPtr(new PluginHandleSet);
377
378     DbPluginHandle handle = INVALID_PLUGIN_HANDLE;
379
380     //register requiredObjects
381     FOREACH(it, *(m_libraryObjects->getDependentObjects()))
382     {
383         if (m_libraryObjects->hasObject(*it)) {
384             LogDebug("Dependency from the same library. ignored");
385             continue;
386         }
387
388         handle = PluginDAO::getPluginHandleForImplementedObject(*it);
389         if (handle == INVALID_PLUGIN_HANDLE) {
390             LogError("Library implementing: " << *it << " NOT FOUND");
391             PluginDAO::setPluginInstallationStatus(
392                 m_pluginHandle,
393                 PluginDAO::INSTALLATION_WAITING);
394             return;
395         }
396
397         handles->insert(handle);
398     }
399
400     PluginDAO::registerPluginLibrariesDependencies(m_pluginHandle, handles);
401
402     PluginDAO::setPluginInstallationStatus(m_pluginHandle,
403                                            PluginDAO::INSTALLATION_COMPLETED);
404
405     //Installation completed
406     m_context->pluginHandle = m_pluginHandle;
407     m_context->installationCompleted = true;
408
409     SET_PLUGIN_INSTALL_PROGRESS(RESOLVE_DEPENDENCIES, "Dependencies resolved");
410 }
411
412 #undef SET_PLUGIN_INSTALL_PROGRESS
413 } //namespace Jobs
414 } //namespace PluginInstall