Initialize Tizen 2.3
[framework/web/wrt-installer.git] / src_wearable / 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/foreach.h>
31 #include <job.h>
32 #include "plugin_install_task.h"
33 #include "job_plugin_install.h"
34 #include "plugin_installer_errors.h"
35 #include "plugin_metafile_reader.h"
36 #include <dpl/wrt-dao-ro/global_config.h>
37 //#include <plugin.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 #include <wrt_plugin_export.h>
43 #include <plugin_path.h>
44 #include <installer_log.h>
45
46 using namespace WrtDB;
47
48 #define SET_PLUGIN_INSTALL_PROGRESS(step, desc)              \
49     m_context->installerTask->UpdateProgress(               \
50         PluginInstallerContext::step, desc);
51
52 #define DISABLE_IF_PLUGIN_WITHOUT_LIB()        \
53     if (m_pluginInfo.m_libraryName.empty()) \
54     {                                          \
55         _W("Plugin without library."); \
56         return;                                \
57     }
58
59 namespace Jobs {
60 namespace PluginInstall {
61 PluginInstallTask::PluginInstallTask(PluginInstallerContext *inCont) :
62     DPL::TaskDecl<PluginInstallTask>(this),
63     m_context(inCont),
64     m_pluginHandle(0),
65     m_dataFromConfigXML(true)
66 {
67     AddStep(&PluginInstallTask::stepCheckPluginPath);
68     AddStep(&PluginInstallTask::stepParseConfigFile);
69     AddStep(&PluginInstallTask::stepFindPluginLibrary);
70     AddStep(&PluginInstallTask::stepCheckIfAlreadyInstalled);
71     AddStep(&PluginInstallTask::stepLoadPluginLibrary);
72     AddStep(&PluginInstallTask::stepRegisterPlugin);
73     AddStep(&PluginInstallTask::stepRegisterFeatures);
74     AddStep(&PluginInstallTask::stepRegisterPluginObjects);
75     AddStep(&PluginInstallTask::stepResolvePluginDependencies);
76
77     SET_PLUGIN_INSTALL_PROGRESS(START, "Installation initialized");
78 }
79
80 PluginInstallTask::~PluginInstallTask()
81 {}
82
83 void PluginInstallTask::stepCheckPluginPath()
84 {
85     _D("Plugin installation: step CheckPluginPath");
86
87     if(!m_context->pluginFilePath.Exists()){
88         ThrowMsg(Exceptions::PluginPathFailed,
89                  "No such path");
90     }
91
92     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Path to plugin verified");
93 }
94
95 void PluginInstallTask::stepParseConfigFile()
96 {
97     _D("Plugin installation: step parse config file");
98
99     if(!m_context->pluginFilePath.getMetaFile().Exists()){
100         m_dataFromConfigXML = false;
101         return;
102     }
103
104     _D("Plugin Config file::%s", m_context->pluginFilePath.getMetaFile().Fullpath().c_str());
105
106     Try
107     {
108         PluginMetafileReader reader;
109         reader.initialize(m_context->pluginFilePath.getMetaFile());
110         reader.read(m_pluginInfo);
111
112         FOREACH(it, m_pluginInfo.m_featureContainer)
113         {
114             _D("Parsed feature : %s", it->m_name.c_str());
115             FOREACH(devCap, it->m_deviceCapabilities) {
116                 _D("  |  DevCap : %s", (*devCap).c_str());
117             }
118         }
119
120         SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_PATH, "Config file analyzed");
121     }
122     Catch(ValidationCore::ParserSchemaException::Base)
123     {
124         _E("Error during file processing %s", m_context->pluginFilePath.getMetaFile().Fullpath().c_str());
125         ThrowMsg(Exceptions::PluginMetafileFailed,
126                  "Metafile error");
127     }
128 }
129
130 void PluginInstallTask::stepFindPluginLibrary()
131 {
132     if (m_dataFromConfigXML) {
133         return;
134     }
135     _D("Plugin installation: step find plugin library");
136     _D("Plugin .so: %s", m_context->pluginFilePath.getLibraryName().c_str());
137     m_pluginInfo.m_libraryName = m_context->pluginFilePath.getLibraryName();
138 }
139
140 void PluginInstallTask::stepCheckIfAlreadyInstalled()
141 {
142     if (PluginDAO::isPluginInstalled(m_pluginInfo.m_libraryName)) {
143         ThrowMsg(Exceptions::PluginAlreadyInstalled,
144                  "Plugin already installed");
145     }
146
147     SET_PLUGIN_INSTALL_PROGRESS(PLUGIN_EXISTS_CHECK, "Check if plugin exist");
148 }
149
150 void PluginInstallTask::stepLoadPluginLibrary()
151 {
152     _D("Plugin installation: step load library");
153
154     DISABLE_IF_PLUGIN_WITHOUT_LIB()
155
156     _D("Loading plugin: %s", m_context->pluginFilePath.getLibraryName().c_str());
157
158     fprintf(stderr, " - Try to dlopen() : [%s] ", m_context->pluginFilePath.getLibraryPath().Fullpath().c_str());
159
160     void *dlHandle = dlopen( m_context->pluginFilePath.getLibraryPath().Fullpath().c_str(), RTLD_LAZY);
161     if (dlHandle == NULL) {
162         const char* error = (const char*)dlerror();
163         fprintf(stderr,
164                 "-> Failed!\n   %s\n",
165                 (error != NULL ? error : "unknown"));
166         _E("Failed to load plugin: %s. Reason: %s",
167             m_context->pluginFilePath.getLibraryName().c_str(), (error != NULL ? error : "unknown"));
168         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
169     }
170
171     fprintf(stderr, "-> Done.\n");
172
173     const js_entity_definition_t *rawEntityList = NULL;
174     get_widget_entity_map_proc *getWidgetEntityMapProcPtr = NULL;
175
176     getWidgetEntityMapProcPtr =
177         reinterpret_cast<get_widget_entity_map_proc *>(dlsym(dlHandle,
178                                                              PLUGIN_GET_CLASS_MAP_PROC_NAME));
179
180     if (getWidgetEntityMapProcPtr) {
181         rawEntityList = (*getWidgetEntityMapProcPtr)();
182     } else {
183         rawEntityList =
184             static_cast<const js_entity_definition_t *>(dlsym(dlHandle,
185                                                               PLUGIN_CLASS_MAP_NAME));
186     }
187
188     if (rawEntityList == NULL) {
189         dlclose(dlHandle);
190         _E("Failed to read class name %s", m_context->pluginFilePath.getLibraryName().c_str());
191         ThrowMsg(Exceptions::PluginLibraryError, "Library error");
192     }
193
194     if (!m_dataFromConfigXML) {
195         on_widget_init_proc *onWidgetInitProc =
196             reinterpret_cast<on_widget_init_proc *>(
197                 dlsym(dlHandle, PLUGIN_WIDGET_INIT_PROC_NAME));
198
199         if (NULL == onWidgetInitProc) {
200             dlclose(dlHandle);
201             _E("Failed to read onWidgetInit symbol %s", m_context->pluginFilePath.getLibraryName().c_str());
202             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
203         }
204
205         // obtain feature -> dev-cap mapping
206         feature_mapping_interface_t mappingInterface = { NULL, NULL, NULL };
207         (*onWidgetInitProc)(&mappingInterface);
208
209         if (!mappingInterface.featGetter || !mappingInterface.release ||
210             !mappingInterface.dcGetter)
211         {
212             _E("Failed to obtain mapping interface from .so");
213             ThrowMsg(Exceptions::PluginLibraryError, "Library error");
214         }
215
216         feature_mapping_t* devcapMapping = mappingInterface.featGetter();
217
218         _D("Getting mapping from features to device capabilities");
219
220         for (size_t i = 0; i < devcapMapping->featuresCount; ++i) {
221             PluginMetafileData::Feature feature;
222             feature.m_name = devcapMapping->features[i].feature_name;
223
224             _D("Feature: %s", feature.m_name.c_str());
225
226             const devcaps_t* dc =
227                 mappingInterface.dcGetter(
228                     devcapMapping,
229                     devcapMapping->features[i].
230                         feature_name);
231
232             if (dc) {
233                 _D("devcaps count: %d", dc->devCapsCount);
234
235                 for (size_t j = 0; j < dc->devCapsCount; ++j) {
236                     _D("devcap: %s", dc->deviceCaps[j]);
237                     feature.m_deviceCapabilities.insert(dc->deviceCaps[j]);
238                 }
239             }
240
241             m_pluginInfo.m_featureContainer.insert(feature);
242         }
243
244         mappingInterface.release(devcapMapping);
245     }
246
247     m_libraryObjects = PluginObjectsPtr(new PluginObjects());
248     const js_entity_definition_t *rawEntityListIterator = rawEntityList;
249
250     _D("#####");
251     _D("##### Plugin: %s supports new plugin API",
252         m_context->pluginFilePath.getLibraryName().c_str());
253     _D("#####");
254
255     while (rawEntityListIterator->parent_name != NULL &&
256            rawEntityListIterator->object_name != NULL)
257     {
258         _D("#####     [%s]: ", rawEntityListIterator->object_name);
259         _D("#####     Parent: %s", rawEntityListIterator->parent_name);
260         _D("#####");
261
262         m_libraryObjects->addObjects(rawEntityListIterator->parent_name,
263                                      rawEntityListIterator->object_name);
264
265         ++rawEntityListIterator;
266     }
267
268     // Unload library
269     if (dlclose(dlHandle) != 0) {
270         _E("Cannot close plugin handle");
271     } else {
272         _D("Library is unloaded");
273     }
274
275     // Load export table
276     _D("Library successfuly loaded and parsed");
277
278     SET_PLUGIN_INSTALL_PROGRESS(LOADING_LIBRARY, "Library loaded and analyzed");
279 }
280
281 void PluginInstallTask::stepRegisterPlugin()
282 {
283     _D("Plugin installation: step register Plugin");
284
285     m_pluginHandle =
286         PluginDAO::registerPlugin(m_pluginInfo, m_context->pluginFilePath.Fullpath());
287
288     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_PLUGIN, "Plugin registered");
289 }
290
291 void PluginInstallTask::stepRegisterFeatures()
292 {
293     _D("Plugin installation: step register features");
294
295     FOREACH(it, m_pluginInfo.m_featureContainer)
296     {
297         _D("PluginHandle: %d", m_pluginHandle);
298         FeatureDAO::RegisterFeature(*it, m_pluginHandle);
299     }
300     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_FEATURES, "Features registered");
301 }
302
303 void PluginInstallTask::stepRegisterPluginObjects()
304 {
305     _D("Plugin installation: step register objects");
306
307     DISABLE_IF_PLUGIN_WITHOUT_LIB()
308
309     //register implemented objects
310     PluginObjects::ObjectsPtr objects =
311         m_libraryObjects->getImplementedObject();
312
313     FOREACH(it, *objects)
314     {
315         PluginDAO::registerPluginImplementedObject(*it, m_pluginHandle);
316     }
317
318     //register requiredObjects
319     objects = m_libraryObjects->getDependentObjects();
320
321     FOREACH(it, *objects)
322     {
323         if (m_libraryObjects->hasObject(*it)) {
324             _D("Dependency from the same library. ignored");
325             continue;
326         }
327
328         PluginDAO::registerPluginRequiredObject(*it, m_pluginHandle);
329     }
330
331     SET_PLUGIN_INSTALL_PROGRESS(REGISTER_OBJECTS, "Plugin Objects registered");
332 }
333
334 void PluginInstallTask::stepResolvePluginDependencies()
335 {
336     _D("Plugin installation: step resolve dependencies ");
337
338     //DISABLE_IF_PLUGIN_WITHOUT_LIB
339     if (m_pluginInfo.m_libraryName.empty()) {
340         PluginDAO::setPluginInstallationStatus(
341             m_pluginHandle,
342             PluginDAO::
343                 INSTALLATION_COMPLETED);
344         //Installation completed
345         m_context->pluginHandle = m_pluginHandle;
346         m_context->installationCompleted = true;
347         _W("Plugin without library.");
348         return;
349     }
350
351     PluginHandleSetPtr handles = PluginHandleSetPtr(new PluginHandleSet);
352
353     DbPluginHandle handle = INVALID_PLUGIN_HANDLE;
354
355     //register requiredObjects
356     FOREACH(it, *(m_libraryObjects->getDependentObjects()))
357     {
358         if (m_libraryObjects->hasObject(*it)) {
359             _D("Dependency from the same library. ignored");
360             continue;
361         }
362
363         handle = PluginDAO::getPluginHandleForImplementedObject(*it);
364         if (handle == INVALID_PLUGIN_HANDLE) {
365             _E("Library implementing: %s NOT FOUND", (*it).c_str());
366             PluginDAO::setPluginInstallationStatus(
367                 m_pluginHandle,
368                 PluginDAO::INSTALLATION_WAITING);
369             return;
370         }
371
372         handles->insert(handle);
373     }
374
375     PluginDAO::registerPluginLibrariesDependencies(m_pluginHandle, handles);
376
377     PluginDAO::setPluginInstallationStatus(m_pluginHandle,
378                                            PluginDAO::INSTALLATION_COMPLETED);
379
380     //Installation completed
381     m_context->pluginHandle = m_pluginHandle;
382     m_context->installationCompleted = true;
383
384     SET_PLUGIN_INSTALL_PROGRESS(RESOLVE_DEPENDENCIES, "Dependencies resolved");
385 }
386
387 #undef SET_PLUGIN_INSTALL_PROGRESS
388 } //namespace Jobs
389 } //namespace PluginInstall