2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file plugin_logic.cpp
18 * @author Piotr Fatyga (p.fatyga@samsung.com)
19 * @author Grzegorz Krawczyk (g.krawczyk@samsung.com)
20 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
22 * @brief This file is the implementation file of plugin and
23 * feature loading routines
24 * @brief This code is intended to work behind view controller
27 #include "plugin_logic.h"
29 #include <dpl/assert.h>
30 #include <dpl/scoped_array.h>
31 #include <dpl/log/log.h>
32 #include <dpl/foreach.h>
33 #include <dpl/singleton_impl.h>
34 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
35 #include <dpl/wrt-dao-ro/common_dao_types.h>
36 #include <dpl/wrt-dao-ro/global_config.h>
38 #include <JavaScriptCore/JavaScript.h>
41 #include <sys/types.h>
52 #include <wrt_plugin_export.h>
53 #include <js_overlay_types.h>
57 #include "plugin_model.h"
58 #include "javascript_interface.h"
59 #include "js_function_manager.h"
60 #include "plugin_container_support.h"
62 #include "js_page_session.h"
65 using namespace WrtDB;
66 using namespace WrtPlugins::W3C;
69 const char *LIBRARY_PATH_SEPARATOR = "/";
72 class JSPageSession::Impl
75 typedef std::set<PluginPtr> LoadedPlugins;
76 typedef std::set<JSGlobalContextRef> LoadedContexts;
79 ///< Widget handle using this session
82 //view for this session
83 JSGlobalContextRef m_context;
85 bool m_sessionStarted;
87 ///< JS object explorer for this session
88 Explorer* m_objectExplorer;
90 PluginContainerSupportPtr m_pluginsSupport;
92 ///< All loaded plugins. Each one must be unloaded. Plugins means
93 //set of features connected with such plugin (library)
94 LoadedPlugins m_loadedPlugins;
96 // Set of currently loaded web pages' contexts. These contexts are
97 // exactly matching with each frames' global context.
98 LoadedContexts m_loadedContexts;
101 PluginPtr loadLibrary(PluginModelPtr& pluginModel);
103 void loadInjectedJavaScript();
104 void installStandardFeatures();
105 void installRootPlugins();
106 void installRequestedFeatures();
108 //returns true if success or false if failed
109 bool installPlugin(PluginModelPtr plugin);
110 bool installPluginOnDemand(PluginModelPtr plugin,
111 JavaScriptObject& parentObject,
112 JSGlobalContextRef context);
114 void unloadPluginsFromSession();
117 Impl(const PluginContainerSupportPtr& containerSupport);
121 void startSession(int widgetHandle,
122 JSGlobalContextRef view,
124 const char* encodedBundle,
129 void performLibrariesUnload();
131 bool loadPluginOnDemand(const WrtDB::DbPluginHandle &pluginHandle,
132 JavaScriptObject& parentObject,
133 JSGlobalContextRef context);
135 void loadFrame(JSGlobalContextRef context);
136 void unloadFrame(JSGlobalContextRef context);
138 void setCustomProperties(double scaleFactor,
139 const char* encodedBundle,
142 void dispatchJavaScriptEvent(CustomEventType eventType, void* data);
145 JSPageSession::Impl::Impl(const PluginContainerSupportPtr& support) :
148 m_sessionStarted(false),
149 m_objectExplorer(NULL)
151 // DPL::Log::LogSystemSingleton::Instance().SetTag("WRT_PLUGINS");
152 LogDebug("Initializing Page Session");
153 m_pluginsSupport = support;
155 // explicit call to keep singleton's lifetime until calling destructor.
156 // JsFunctionManagerSingleton::Instance();
157 // JavaScriptInterfaceSingleton::Instance();
160 JSPageSession::Impl::~Impl()
162 if (m_sessionStarted) {
163 LogError("Must stop widget session before exit!");
167 LogDebug("Deinitializing plugin Logic...");
170 void JSPageSession::Impl::installStandardFeatures()
172 LogInfo("Installing standard widget features...");
174 //add standard functions
175 FOREACH(it, JsFunctionManagerSingleton::Instance().getFunctions())
177 m_objectExplorer->registerObject(*it, NULL);
180 //add standard objects
181 LogDebug("Installing standard extensions...");
183 auto standardPlugins = m_pluginsSupport->getStandardPlugins();
184 FOREACH(it, standardPlugins)
186 //loadFeatureToSession(*it);
190 LogInfo("Standard widget features installed.");
193 void JSPageSession::Impl::installRootPlugins()
195 LogInfo("Installing requested root plugins...");
197 PluginContainerSupport::PluginsList rootPlugins =
198 m_pluginsSupport->getRootPlugins();
199 FOREACH(it, rootPlugins)
204 LogInfo("requested root plugins installed.");
207 bool JSPageSession::Impl::installPlugin(PluginModelPtr plugin)
209 Assert(plugin && "Plugin Model is NULL");
210 auto library = loadLibrary(plugin);
212 LogInfo("Install Plugin '" << library->GetFileName());
215 LogError("Loading library failed");
219 // Register new class
220 FOREACH(it, *(library->GetClassList()))
222 if (!m_objectExplorer->registerObject(*it, NULL)) {
223 LogError("Object Registration failed : " << (*it)->getName());
227 LogDebug("Registered feature.");
231 void JSPageSession::Impl::installRequestedFeatures()
233 LogInfo("Installing requested widget features...");
235 std::list<std::string> allowedFeatures =
236 m_pluginsSupport->getAllowedFeatures(m_widgetHandle);
238 PluginContainerSupport::PluginsList allowedPlugins;
240 FOREACH(feature, allowedFeatures)
242 LogDebug("Processing feature: " << *feature);
244 auto plugin = m_pluginsSupport->getPluginForFeature(*feature);
245 ImplementedObjectsList implObjs =
247 getImplementedObjectsForPluginHandle(plugin->Handle.Get());
249 FOREACH(obj, implObjs)
251 LogDebug("Processing object: " << *obj);
252 /* This can be optimalized, but would need extra data in database.
253 * There should be a list of features that are allowed to be
254 * installed at widget start */
255 if (obj->find(".") == obj->rfind(".")) {
256 allowedPlugins.push_back(plugin);
257 LogWarning("Plugin will be added: "
258 << plugin->LibraryName.Get());
264 FOREACH(plugin, allowedPlugins)
266 LogDebug("Installation plugin: " << (*plugin)->LibraryName.Get());
267 installPlugin(*plugin);
270 LogInfo("requested features installed.");
273 bool JSPageSession::Impl::loadPluginOnDemand(
274 const WrtDB::DbPluginHandle &pluginHandle,
275 JavaScriptObject& parentObject,
276 JSGlobalContextRef context)
278 LogDebug("load plugin with feature");
280 Assert(parentObject.instance &&
281 !parentObject.name.empty()
282 && "Wrong arguments");
284 if (!m_sessionStarted) {
285 LogError("Session not started");
288 // //TODO here may be a bug. if plugin contains feature rejected and
290 // LogInfo("Installing feature : " << widgetFeature.name);
291 // if (widgetFeature.rejected) {
292 // LogWarning("This api-feature was rejected");
296 // auto plugin = m_pluginsSupport->getPluginModelById(pluginHandle);
298 // LogError("Failed to load plugin. plugin handle: " <<
302 m_pluginsSupport->registerPluginModel(pluginHandle);
303 return installPluginOnDemand(
304 m_pluginsSupport->getPluginModelById(pluginHandle),
309 bool JSPageSession::Impl::installPluginOnDemand(PluginModelPtr plugin,
310 JavaScriptObject& parentObject,
311 JSGlobalContextRef context)
313 Assert(plugin && "Plugin Model is NULL");
314 auto library = loadLibrary(plugin);
316 LogInfo("Install Plugin '" << library->GetFileName());
319 LogError("Loading library failed");
323 if (!(parentObject.instance)) {
324 LogError("NULL pointer value");
328 JSObjectPtr parent(new JSObject(parentObject.instance));
330 if (!parent->getObject()) {
331 LogError("NULL pointer value");
336 FOREACH(it, *(library->GetClassList()))
338 bool installationStatus =
339 m_objectExplorer->registerObject(*it,
344 if (!installationStatus) {
346 "Object Registration failed : " << (*it)->getName()
348 "; Parent object name: " << parentObject.name);
353 LogDebug("Plugin on demand registration completed");
357 void JSPageSession::Impl::setCustomProperties(double scaleFactor,
358 const char* encodedBundle,
362 "set properties of window object " << scaleFactor << ", "
363 << encodedBundle << ", " <<
366 m_objectExplorer->getWindowPropertySupport()
367 ->setScaleToNavigatorProperty(scaleFactor);
368 m_objectExplorer->getWindowPropertySupport()
369 ->setBundleToWindowProperty(encodedBundle);
370 m_objectExplorer->getWindowPropertySupport()
371 ->setThemeToNavigatorProperty(theme);
374 void JSPageSession::Impl::dispatchJavaScriptEvent(CustomEventType eventType,
377 // Check if session is already started
378 if (!m_sessionStarted) {
379 LogWarning("Session not started!");
383 LogInfo("Request dispatching javascript event");
384 m_objectExplorer->callEventListeners(eventType, data);
387 void JSPageSession::Impl::loadInjectedJavaScript()
391 std::string DIR_PATH = "/usr/etc/wrt/injected-javascript";
392 std::string JS_EXTENSION = ".js";
394 DIR *dir = opendir(DIR_PATH.c_str());
397 LogError("opendir(\"" << DIR_PATH << "\") error!");
402 struct dirent libdir;
403 struct dirent* result;
404 std::list<std::string> jsFiles;
406 // make file list from DIR_PATH
407 for (return_code = readdir_r(dir, &libdir, &result);
408 result != NULL && return_code == 0;
409 return_code = readdir_r(dir, &libdir, &result)) {
410 if (strncmp(libdir.d_name, ".", 2) == 0 ||
411 strncmp(libdir.d_name, "..", 3) == 0)
416 std::string filepath = DIR_PATH;
418 filepath += libdir.d_name;
420 std::string lowercase = filepath;
421 std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(),
424 if (lowercase.rfind(JS_EXTENSION) == std::string::npos ||
425 lowercase.length() !=
426 lowercase.rfind(JS_EXTENSION) + JS_EXTENSION.length() )
428 LogError("This is not js file" << filepath);
434 if (stat(filepath.c_str(), &tmp) == -1) {
435 LogError("Failed to open file " << filepath);
439 if (!S_ISREG(tmp.st_mode)) {
440 LogError("This is not a regular file " << filepath);
444 LogInfo("Added : " << filepath);
445 jsFiles.push_back(filepath);
447 if (0 != return_code)
448 LogError("Error while reading directory.");
454 LogDebug("load file : " << (*it));
457 std::ifstream fin(it->c_str());
461 std::getline(fin, line);
462 content += line + "\n";
467 if (!content.empty()) {
468 JSValueRef exception = NULL;
470 JSStringCreateWithUTF8CString(content.c_str());
472 JSEvaluateScript(m_context, script, NULL, NULL, 1, &exception);
474 JSStringRelease(script);
477 LogDebug("Exception Occured while injecting javascript "
480 JSStringRef exceptionJSString =
481 JSValueToStringCopy(m_context, exception, NULL);
483 JSStringGetMaximumUTF8CStringSize(exceptionJSString);
484 char* exceptionString = new char[size];
485 JSStringGetUTF8CString(exceptionJSString,
486 exceptionString, size);
487 LogDebug("Exception : " << exceptionString);
489 delete[] exceptionString;
490 JSStringRelease(exceptionJSString);
496 void JSPageSession::Impl::startSession(int widgetHandle,
497 JSGlobalContextRef context,
499 const char* encodedBundle,
502 LogInfo("Starting widget session...");
504 // Check if corresponding session if not already created
505 if (m_sessionStarted) {
506 LogWarning("Session already started!");
510 // Create js object explorer object
511 m_objectExplorer = new Explorer(context);
513 m_sessionStarted = true;
514 m_widgetHandle = widgetHandle;
515 m_loadedPlugins.clear();
518 // Register standard features
519 installStandardFeatures();
521 WidgetDAOReadOnly dao(m_widgetHandle);
522 WidgetType appType = dao.getWidgetType();
523 if (appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
524 installRootPlugins();
526 // Register special features
527 installRequestedFeatures();
529 // set scale, bundle as window's property
530 setCustomProperties(scaleFactor, encodedBundle, theme);
532 // Load injected javascript files
533 loadInjectedJavaScript();
534 LogInfo("Widget session started.");
537 void JSPageSession::Impl::stopSession()
539 LogInfo("Stopping widget session...");
541 if (!m_sessionStarted) {
542 LogWarning("Session not started!");
546 unloadPluginsFromSession();
547 m_sessionStarted = false;
549 LogInfo("Widget session stopped.");
552 void JSPageSession::Impl::unloadPluginsFromSession()
554 LogDebug("Unload plugins from session");
556 m_objectExplorer->removePluginsFromIframes();
557 m_objectExplorer->cleanIframesData();
559 // delete js object for overlayed js functions
560 FOREACH(it, JsFunctionManagerSingleton::Instance().getFunctions())
562 m_objectExplorer->deregisterObject(*it);
565 // delete js object for plugins
566 FOREACH(pluginIt, m_loadedPlugins)
568 LogDebug("Unregistering plugin " << (*pluginIt)->GetFileName());
570 (*pluginIt)->OnWidgetStop(m_widgetHandle);
571 LogDebug("Emitted WidgetStop for plugin: " <<
572 (*pluginIt)->GetFileName());
574 FOREACH(it, *((*pluginIt)->GetClassList()))
576 m_objectExplorer->deregisterObject(*it);
580 JavaScriptInterfaceSingleton::Instance().invokeGarbageCollector(m_context);
582 m_loadedPlugins.clear();
584 delete m_objectExplorer;
585 m_objectExplorer = NULL;
588 void JSPageSession::Impl::performLibrariesUnload()
591 LogDebug("Perform library unload");
593 size_t unloadedLibraries = 0;
595 FOREACH(pluginIt, m_loadedPlugins)
597 LogDebug("Preparing library: " << (*pluginIt)->LibraryName.Get());
599 PluginPtr plugin = (*pluginIt)->LibraryInstance.Get();
601 LogWarning("Library not loaded " << (*pluginIt)->LibraryName.Get());
605 (*pluginIt)->LibraryInstance.Set(PluginPtr());
608 LogInfo("unloaded " << unloadedLibraries << " unreferenced libraries!");
612 PluginPtr JSPageSession::Impl::loadLibrary(PluginModelPtr& pluginModel)
614 PluginPtr pluginLib = pluginModel->LibraryInstance.Get();
616 std::string path = pluginModel->LibraryPath.Get() +
617 std::string(LIBRARY_PATH_SEPARATOR) +
618 pluginModel->LibraryName.Get();
620 pluginLib = Plugin::LoadFromFile(path);
623 LogError("Loading library failed");
625 pluginModel->LibraryInstance.Set(pluginLib);
627 LogDebug("On widget start");
628 // This is first time for this plugin, start widget Session
629 pluginLib->OnWidgetStart(
631 m_loadedPlugins.insert(pluginLib);
633 FOREACH(context, m_loadedContexts)
635 pluginLib->OnFrameLoad(*context);
639 LogDebug("Get from LibraryInstance");
640 LogDebug("On widget start");
641 // This is first time for this plugin, start widget Session
642 pluginLib->OnWidgetStart(
644 m_loadedPlugins.insert(pluginLib);
646 FOREACH(context, m_loadedContexts)
648 pluginLib->OnFrameLoad(*context);
655 void JSPageSession::Impl::loadFrame(JSGlobalContextRef context)
657 LogDebug("Load a frame");
659 if (!m_sessionStarted) {
660 LogWarning("Session NOT started!");
664 m_loadedContexts.insert(context);
666 FOREACH(pluginIt, m_loadedPlugins)
668 LogDebug("load plugin to frame" << (*pluginIt)->GetFileName());
670 (*pluginIt)->OnFrameLoad(context);
673 m_objectExplorer->loadFrame(context);
676 void JSPageSession::Impl::unloadFrame(JSGlobalContextRef context)
678 LogDebug("Unload a frame");
680 if (!m_sessionStarted) {
681 LogWarning("Session NOT started!");
685 m_loadedContexts.erase(context);
687 FOREACH(pluginIt, m_loadedPlugins)
689 LogDebug("unload plugin to frame" << (*pluginIt)->GetFileName());
691 (*pluginIt)->OnFrameUnload(context);
694 m_objectExplorer->unloadFrame(context);
697 void JSPageSession::startSession(int widgetHandle,
698 JSGlobalContextRef ctx,
700 const char* encodedBundle,
703 m_impl->startSession(widgetHandle, ctx, scaleFactor, encodedBundle, theme);
706 void JSPageSession::stopSession()
708 m_impl->stopSession();
711 void JSPageSession::performLibrariesUnload()
713 m_impl->performLibrariesUnload();
716 bool JSPageSession::loadPluginOnDemand(
717 const WrtDB::DbPluginHandle &pluginHandle,
718 JavaScriptObject& parentObject,
719 JSGlobalContextRef context)
721 return m_impl->loadPluginOnDemand(pluginHandle, parentObject, context);
724 void JSPageSession::setCustomProperties(double scaleFactor,
725 const char* encodedBundle,
728 m_impl->setCustomProperties(scaleFactor, encodedBundle, theme);
731 void JSPageSession::dispatchJavaScriptEvent(CustomEventType eventType,
734 m_impl->dispatchJavaScriptEvent(eventType, data);
737 void JSPageSession::loadFrame(JSGlobalContextRef context)
739 m_impl->loadFrame(context);
742 void JSPageSession::unloadFrame(JSGlobalContextRef context)
744 m_impl->unloadFrame(context);
747 JSPageSession::JSPageSession(const PluginContainerSupportPtr& containerSupport)
749 m_impl(new JSPageSession::Impl(containerSupport))
752 JSPageSession::~JSPageSession()