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