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