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 = "/";
70 const char *TIZEN_ROOT_FEATURES = "http://tizen.org/privilege/tizen";
73 class JSPageSession::Impl
76 typedef std::set<PluginPtr> LoadedPlugins;
77 typedef std::set<JSGlobalContextRef> LoadedContexts;
80 ///< Widget handle using this session
83 //view for this session
84 JSGlobalContextRef m_context;
86 bool m_sessionStarted;
88 ///< JS object explorer for this session
89 Explorer* m_objectExplorer;
91 PluginContainerSupportPtr m_pluginsSupport;
93 ///< All loaded plugins. Each one must be unloaded. Plugins means
94 //set of features connected with such plugin (library)
95 LoadedPlugins m_loadedPlugins;
97 // Set of currently loaded web pages' contexts. These contexts are
98 // exactly matching with each frames' global context.
99 LoadedContexts m_loadedContexts;
102 PluginPtr loadLibrary(PluginModelPtr& pluginModel);
104 void loadInjectedJavaScript();
105 void installStandardFeatures();
106 void installRootFeatures();
107 void installRequestedFeatures();
109 //returns true if success or false if failed
110 bool installPlugin(PluginModelPtr plugin);
111 bool installPluginOnDemand(PluginModelPtr plugin,
112 JavaScriptObject& parentObject,
113 JSGlobalContextRef context);
115 void unloadPluginsFromSession();
118 Impl(const PluginContainerSupportPtr& containerSupport);
122 void startSession(int widgetHandle,
123 JSGlobalContextRef view,
125 const char* encodedBundle,
130 void performLibrariesUnload();
132 bool loadPluginOnDemand(const WrtDB::DbPluginHandle &pluginHandle,
133 JavaScriptObject& parentObject,
134 JSGlobalContextRef context);
136 void loadFrame(JSGlobalContextRef context);
137 void unloadFrame(JSGlobalContextRef context);
139 void setCustomProperties(double scaleFactor,
140 const char* encodedBundle,
143 void dispatchJavaScriptEvent(CustomEventType eventType, void* data);
146 JSPageSession::Impl::Impl(const PluginContainerSupportPtr& support) :
149 m_sessionStarted(false),
150 m_objectExplorer(NULL)
152 // DPL::Log::LogSystemSingleton::Instance().SetTag("WRT_PLUGINS");
153 LogDebug("Initializing Page Session");
154 m_pluginsSupport = support;
156 // explicit call to keep singleton's lifetime until calling destructor.
157 // JsFunctionManagerSingleton::Instance();
158 // JavaScriptInterfaceSingleton::Instance();
161 JSPageSession::Impl::~Impl()
163 if (m_sessionStarted) {
164 LogError("Must stop widget session before exit!");
168 LogDebug("Deinitializing plugin Logic...");
171 void JSPageSession::Impl::installStandardFeatures()
173 LogInfo("Installing standard widget features...");
175 //add standard functions
176 FOREACH(it, JsFunctionManagerSingleton::Instance().getFunctions())
178 m_objectExplorer->registerObject(*it, NULL);
181 //add standard objects
182 LogDebug("Installing standard extensions...");
184 auto standardPlugins = m_pluginsSupport->getStandardPlugins();
185 FOREACH(it, standardPlugins)
187 //loadFeatureToSession(*it);
191 LogInfo("Standard widget features installed.");
194 void JSPageSession::Impl::installRootFeatures()
196 LogInfo("Installing requested widget features...");
197 WrtDB::FeatureDAOReadOnly dao(TIZEN_ROOT_FEATURES);
198 auto plugin = m_pluginsSupport->getPluginModelById(dao.GetPluginHandle());
199 installPlugin(plugin);
200 LogInfo("requested root feature installed.");
203 bool JSPageSession::Impl::installPlugin(PluginModelPtr plugin)
205 Assert(plugin && "Plugin Model is NULL");
206 auto library = loadLibrary(plugin);
208 LogInfo("Install Plugin '" << library->GetFileName());
211 LogError("Loading library failed");
215 // Register new class
216 FOREACH(it, *(library->GetClassList()))
218 if (!m_objectExplorer->registerObject(*it, NULL)) {
219 LogError("Object Registration failed : " << (*it)->getName());
223 LogDebug("Registered feature.");
227 void JSPageSession::Impl::installRequestedFeatures()
229 LogInfo("Installing requested widget features...");
231 std::list<std::string> allowedFeatures =
232 m_pluginsSupport->getAllowedFeatures(m_widgetHandle);
234 PluginContainerSupport::PluginsList allowedPlugins;
236 FOREACH(feature, allowedFeatures)
238 LogDebug("Processing feature: " << *feature);
240 auto plugin = m_pluginsSupport->getPluginForFeature(*feature);
241 ImplementedObjectsList implObjs =
243 getImplementedObjectsForPluginHandle(plugin->Handle.Get());
245 FOREACH(obj, implObjs)
247 LogDebug("Processing object: " << *obj);
248 /* This can be optimalized, but would need extra data in database.
249 * There should be a list of features that are allowed to be
250 * installed at widget start */
251 if (obj->find(".") == obj->rfind(".")) {
252 allowedPlugins.push_back(plugin);
253 LogWarning("Plugin will be added: "
254 << plugin->LibraryName.Get());
260 FOREACH(plugin, allowedPlugins)
262 LogDebug("Installation plugin: " << (*plugin)->LibraryName.Get());
263 installPlugin(*plugin);
266 LogInfo("requested features installed.");
269 bool JSPageSession::Impl::loadPluginOnDemand(
270 const WrtDB::DbPluginHandle &pluginHandle,
271 JavaScriptObject& parentObject,
272 JSGlobalContextRef context)
274 LogDebug("load plugin with feature");
276 Assert(parentObject.instance &&
277 !parentObject.name.empty()
278 && "Wrong arguments");
280 if (!m_sessionStarted) {
281 LogError("Session not started");
284 // //TODO here may be a bug. if plugin contains feature rejected and
286 // LogInfo("Installing feature : " << widgetFeature.name);
287 // if (widgetFeature.rejected) {
288 // LogWarning("This api-feature was rejected");
292 // auto plugin = m_pluginsSupport->getPluginModelById(pluginHandle);
294 // LogError("Failed to load plugin. plugin handle: " <<
298 m_pluginsSupport->registerPluginModel(pluginHandle);
299 return installPluginOnDemand(
300 m_pluginsSupport->getPluginModelById(pluginHandle),
305 bool JSPageSession::Impl::installPluginOnDemand(PluginModelPtr plugin,
306 JavaScriptObject& parentObject,
307 JSGlobalContextRef context)
309 Assert(plugin && "Plugin Model is NULL");
310 auto library = loadLibrary(plugin);
312 LogInfo("Install Plugin '" << library->GetFileName());
315 LogError("Loading library failed");
319 if (!(parentObject.instance)) {
320 LogError("NULL pointer value");
324 JSObjectPtr parent(new JSObject(parentObject.instance));
326 if (!parent->getObject()) {
327 LogError("NULL pointer value");
332 FOREACH(it, *(library->GetClassList()))
334 bool installationStatus =
335 m_objectExplorer->registerObject(*it,
340 if (!installationStatus) {
342 "Object Registration failed : " << (*it)->getName()
344 "; Parent object name: " << parentObject.name);
349 LogDebug("Plugin on demand registration completed");
353 void JSPageSession::Impl::setCustomProperties(double scaleFactor,
354 const char* encodedBundle,
358 "set properties of window object " << scaleFactor << ", "
359 << encodedBundle << ", " <<
362 m_objectExplorer->getWindowPropertySupport()
363 ->setScaleToNavigatorProperty(scaleFactor);
364 m_objectExplorer->getWindowPropertySupport()
365 ->setBundleToWindowProperty(encodedBundle);
366 m_objectExplorer->getWindowPropertySupport()
367 ->setThemeToNavigatorProperty(theme);
370 void JSPageSession::Impl::dispatchJavaScriptEvent(CustomEventType eventType,
373 // Check if session is already started
374 if (!m_sessionStarted) {
375 LogWarning("Session not started!");
379 LogInfo("Request dispatching javascript event");
380 m_objectExplorer->callEventListeners(eventType, data);
383 void JSPageSession::Impl::loadInjectedJavaScript()
387 std::string DIR_PATH = "/usr/etc/wrt/injected-javascript";
388 std::string JS_EXTENSION = ".js";
390 DIR *dir = opendir(DIR_PATH.c_str());
393 LogError("opendir(\"" << DIR_PATH << "\") error!");
398 struct dirent libdir;
399 struct dirent* result;
400 std::list<std::string> jsFiles;
402 // make file list from DIR_PATH
403 for (return_code = readdir_r(dir, &libdir, &result);
404 result != NULL && return_code == 0;
405 return_code = readdir_r(dir, &libdir, &result)) {
406 if (strncmp(libdir.d_name, ".", 2) == 0 ||
407 strncmp(libdir.d_name, "..", 3) == 0)
412 std::string filepath = DIR_PATH;
414 filepath += libdir.d_name;
416 std::string lowercase = filepath;
417 std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(),
420 if (lowercase.rfind(JS_EXTENSION) == std::string::npos ||
421 lowercase.length() !=
422 lowercase.rfind(JS_EXTENSION) + JS_EXTENSION.length() )
424 LogError("This is not js file" << filepath);
430 if (stat(filepath.c_str(), &tmp) == -1) {
431 LogError("Failed to open file " << filepath);
435 if (!S_ISREG(tmp.st_mode)) {
436 LogError("This is not a regular file " << filepath);
440 LogInfo("Added : " << filepath);
441 jsFiles.push_back(filepath);
443 if (0 != return_code)
444 LogError("Error while reading directory.");
450 LogDebug("load file : " << (*it));
453 std::ifstream fin(it->c_str());
457 std::getline(fin, line);
458 content += line + "\n";
463 if (!content.empty()) {
464 JSValueRef exception = NULL;
466 JSStringCreateWithUTF8CString(content.c_str());
468 JSEvaluateScript(m_context, script, NULL, NULL, 1, &exception);
470 JSStringRelease(script);
473 LogDebug("Exception Occured while injecting javascript "
476 JSStringRef exceptionJSString =
477 JSValueToStringCopy(m_context, exception, NULL);
479 JSStringGetMaximumUTF8CStringSize(exceptionJSString);
480 char* exceptionString = new char[size];
481 JSStringGetUTF8CString(exceptionJSString,
482 exceptionString, size);
483 LogDebug("Exception : " << exceptionString);
485 delete[] exceptionString;
486 JSStringRelease(exceptionJSString);
492 void JSPageSession::Impl::startSession(int widgetHandle,
493 JSGlobalContextRef context,
495 const char* encodedBundle,
498 LogInfo("Starting widget session...");
500 // Check if corresponding session if not already created
501 if (m_sessionStarted) {
502 LogWarning("Session already started!");
506 // Create js object explorer object
507 m_objectExplorer = new Explorer(context);
509 m_sessionStarted = true;
510 m_widgetHandle = widgetHandle;
511 m_loadedPlugins.clear();
514 // Register standard features
515 installStandardFeatures();
517 WidgetDAOReadOnly dao(m_widgetHandle);
518 WidgetType appType = dao.getWidgetType();
519 if (appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
520 installRootFeatures();
522 // Register special features
523 installRequestedFeatures();
525 // set scale, bundle as window's property
526 setCustomProperties(scaleFactor, encodedBundle, theme);
528 // Load injected javascript files
529 loadInjectedJavaScript();
530 LogInfo("Widget session started.");
533 void JSPageSession::Impl::stopSession()
535 LogInfo("Stopping widget session...");
537 if (!m_sessionStarted) {
538 LogWarning("Session not started!");
542 unloadPluginsFromSession();
543 m_sessionStarted = false;
545 LogInfo("Widget session stopped.");
548 void JSPageSession::Impl::unloadPluginsFromSession()
550 LogDebug("Unload plugins from session");
552 m_objectExplorer->removePluginsFromIframes();
553 m_objectExplorer->cleanIframesData();
555 // delete js object for overlayed js functions
556 FOREACH(it, JsFunctionManagerSingleton::Instance().getFunctions())
558 m_objectExplorer->deregisterObject(*it);
561 // delete js object for plugins
562 FOREACH(pluginIt, m_loadedPlugins)
564 LogDebug("Unregistering plugin " << (*pluginIt)->GetFileName());
566 (*pluginIt)->OnWidgetStop(m_widgetHandle);
567 LogDebug("Emitted WidgetStop for plugin: " <<
568 (*pluginIt)->GetFileName());
570 FOREACH(it, *((*pluginIt)->GetClassList()))
572 m_objectExplorer->deregisterObject(*it);
576 JavaScriptInterfaceSingleton::Instance().invokeGarbageCollector(m_context);
578 m_loadedPlugins.clear();
580 delete m_objectExplorer;
581 m_objectExplorer = NULL;
584 void JSPageSession::Impl::performLibrariesUnload()
587 LogDebug("Perform library unload");
589 size_t unloadedLibraries = 0;
591 FOREACH(pluginIt, m_loadedPlugins)
593 LogDebug("Preparing library: " << (*pluginIt)->LibraryName.Get());
595 PluginPtr plugin = (*pluginIt)->LibraryInstance.Get();
597 LogWarning("Library not loaded " << (*pluginIt)->LibraryName.Get());
601 (*pluginIt)->LibraryInstance.Set(PluginPtr());
604 LogInfo("unloaded " << unloadedLibraries << " unreferenced libraries!");
608 PluginPtr JSPageSession::Impl::loadLibrary(PluginModelPtr& pluginModel)
610 PluginPtr pluginLib = pluginModel->LibraryInstance.Get();
612 std::string path = pluginModel->LibraryPath.Get() +
613 std::string(LIBRARY_PATH_SEPARATOR) +
614 pluginModel->LibraryName.Get();
616 pluginLib = Plugin::LoadFromFile(path);
619 LogError("Loading library failed");
621 pluginModel->LibraryInstance.Set(pluginLib);
623 LogDebug("On widget start");
624 // This is first time for this plugin, start widget Session
625 pluginLib->OnWidgetStart(
627 m_loadedPlugins.insert(pluginLib);
629 FOREACH(context, m_loadedContexts)
631 pluginLib->OnFrameLoad(*context);
635 LogDebug("Get from LibraryInstance");
636 LogDebug("On widget start");
637 // This is first time for this plugin, start widget Session
638 pluginLib->OnWidgetStart(
640 m_loadedPlugins.insert(pluginLib);
642 FOREACH(context, m_loadedContexts)
644 pluginLib->OnFrameLoad(*context);
651 void JSPageSession::Impl::loadFrame(JSGlobalContextRef context)
653 LogDebug("Load a frame");
655 if (!m_sessionStarted) {
656 LogWarning("Session NOT started!");
660 m_loadedContexts.insert(context);
662 FOREACH(pluginIt, m_loadedPlugins)
664 LogDebug("load plugin to frame" << (*pluginIt)->GetFileName());
666 (*pluginIt)->OnFrameLoad(context);
669 m_objectExplorer->loadFrame(context);
672 void JSPageSession::Impl::unloadFrame(JSGlobalContextRef context)
674 LogDebug("Unload a frame");
676 if (!m_sessionStarted) {
677 LogWarning("Session NOT started!");
681 m_loadedContexts.erase(context);
683 FOREACH(pluginIt, m_loadedPlugins)
685 LogDebug("unload plugin to frame" << (*pluginIt)->GetFileName());
687 (*pluginIt)->OnFrameUnload(context);
690 m_objectExplorer->unloadFrame(context);
693 void JSPageSession::startSession(int widgetHandle,
694 JSGlobalContextRef ctx,
696 const char* encodedBundle,
699 m_impl->startSession(widgetHandle, ctx, scaleFactor, encodedBundle, theme);
702 void JSPageSession::stopSession()
704 m_impl->stopSession();
707 void JSPageSession::performLibrariesUnload()
709 m_impl->performLibrariesUnload();
712 bool JSPageSession::loadPluginOnDemand(
713 const WrtDB::DbPluginHandle &pluginHandle,
714 JavaScriptObject& parentObject,
715 JSGlobalContextRef context)
717 return m_impl->loadPluginOnDemand(pluginHandle, parentObject, context);
720 void JSPageSession::setCustomProperties(double scaleFactor,
721 const char* encodedBundle,
724 m_impl->setCustomProperties(scaleFactor, encodedBundle, theme);
727 void JSPageSession::dispatchJavaScriptEvent(CustomEventType eventType,
730 m_impl->dispatchJavaScriptEvent(eventType, data);
733 void JSPageSession::loadFrame(JSGlobalContextRef context)
735 m_impl->loadFrame(context);
738 void JSPageSession::unloadFrame(JSGlobalContextRef context)
740 m_impl->unloadFrame(context);
743 JSPageSession::JSPageSession(const PluginContainerSupportPtr& containerSupport)
745 m_impl(new JSPageSession::Impl(containerSupport))
748 JSPageSession::~JSPageSession()