%files
%attr(755,root,root) %{_bindir}/wrt
%attr(755,root,root) %{_bindir}/wrt-extension
+%attr(755,root,root) %{_bindir}/wrt-extension-client-test
%attr(644,root,root) %{_datadir}/edje/wrt/wrt.edj
%attr(644,root,root) %{_libdir}/libwrt-injected-bundle.so
# Dependencies
PKG_CHECK_MODULES(TARGET_INJECTED_BUNDLE_DEPS REQUIRED
dlog
+ glib-2.0
+ gio-2.0
+ uuid
elementary
chromium-efl
)
# Source Files
SET(TARGET_INJECTED_BUNDLE_SRCS
${BASE_SRCDIR}/bundle/injected_bundle.cc
+ ${BASE_SRCDIR}/bundle/extension_renderer_controller.cc
+ ${BASE_SRCDIR}/bundle/extension_client.cc
+ ${BASE_SRCDIR}/bundle/extension_module.cc
+ ${BASE_SRCDIR}/bundle/module_system.cc
)
INCLUDE_DIRECTORIES(${TARGET_INJECTED_BUNDLE_INCS})
)
+# Build Executable for Test
+SET(TARGET_EXTENSION_TEST "wrt-extension-client-test")
+INCLUDE_DIRECTORIES(
+ ${BASE_SRCDIR}
+ ${TARGET_INJECTED_BUNDLE_INCS})
+ADD_EXECUTABLE(${TARGET_EXTENSION_TEST}
+ ${BASE_SRCDIR}/bundle/extension_client.cc
+ ${BASE_SRCDIR}/bundle/extension_client_test.cc)
+TARGET_LINK_LIBRARIES(${TARGET_EXTENSION_TEST}
+ ${TARGET_COMMON_STATIC}
+ ${TARGET_INJECTED_BUNDLE_LIBS}
+ "-ldl"
+)
+
+INSTALL(TARGETS ${TARGET_EXTENSION_TEST} DESTINATION bin)
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bundle/extension_client.h"
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string>
+
+#include "common/logger.h"
+#include "common/constants.h"
+#include "common/profiler.h"
+#include "common/string_utils.h"
+
+namespace wrt {
+
+ExtensionClient::ExtensionClient() {
+}
+
+ExtensionClient::~ExtensionClient() {
+ auto it = extension_apis_.begin();
+ for ( ; it != extension_apis_.end(); ++it) {
+ delete it->second;
+ }
+}
+
+std::string ExtensionClient::CreateInstance(
+ const std::string& extension_name, InstanceHandler* handler) {
+ GVariant* value = dbus_extension_client_.Call(
+ kDBusInterfaceNameForExtension, kMethodCreateInstance,
+ g_variant_new("(s)", extension_name.c_str()),
+ G_VARIANT_TYPE("(s)"));
+
+ if (!value) {
+ LoggerE("Failed to create instance for extension %s",
+ extension_name.c_str());
+ return std::string();
+ }
+
+ gchar* instance_id;
+ g_variant_get(value, "(&s)", &instance_id);
+
+ std::string ret(instance_id);
+ handlers_[ret] = handler;
+
+ return ret;
+}
+
+void ExtensionClient::DestroyInstance(const std::string& instance_id) {
+ GVariant* value = dbus_extension_client_.Call(
+ kDBusInterfaceNameForExtension, kMethodDestroyInstance,
+ g_variant_new("(s)", instance_id.c_str()),
+ G_VARIANT_TYPE("(s)"));
+
+ if (!value) {
+ LoggerE("Failed to destroy instance %s", instance_id.c_str());
+ return;
+ }
+
+ auto it = handlers_.find(instance_id);
+ if (it != handlers_.end()) {
+ handlers_.erase(it);
+ }
+}
+
+void ExtensionClient::PostMessageToNative(
+ const std::string& instance_id, const std::string& msg) {
+ GVariant* value = dbus_extension_client_.Call(
+ kDBusInterfaceNameForExtension, kMethodPostMessage,
+ g_variant_new("(ss)", instance_id.c_str(), msg.c_str()),
+ NULL);
+}
+
+std::string ExtensionClient::SendSyncMessageToNative(
+ const std::string& instance_id, const std::string& msg) {
+ GVariant* value = dbus_extension_client_.Call(
+ kDBusInterfaceNameForExtension, kMethodSendSyncMessage,
+ g_variant_new("(ss)", instance_id.c_str(), msg.c_str()),
+ G_VARIANT_TYPE("(s)"));
+
+ if (!value) {
+ LoggerE("Failed to send synchronous message to ExtensionServer.");
+ return std::string();
+ }
+
+ gchar* reply;
+ g_variant_get(value, "(&s)", &reply);
+
+ return std::string(reply);
+}
+
+void ExtensionClient::Initialize(const std::string& uuid) {
+ // Connect to DBusServer for ExtensionServer
+ if (dbus_extension_client_.ConnectByName(
+ uuid + "." + std::string(kDBusNameForExtension))) {
+ using std::placeholders::_1;
+ using std::placeholders::_2;
+ dbus_extension_client_.SetSignalCallback(
+ kDBusInterfaceNameForExtension,
+ std::bind(&ExtensionClient::HandleSignal, this, _1, _2));
+ } else {
+ LoggerE("Failed to connect to the dbus server for Extension.");
+ return;
+ }
+
+ // get extensions from ExtensionServer
+ GVariant* value = dbus_extension_client_.Call(
+ kDBusInterfaceNameForExtension, kMethodGetExtensions,
+ NULL,
+ G_VARIANT_TYPE("(a(ssas))"));
+
+ if (!value) {
+ LoggerE("Failed to get extension list from ExtensionServer.");
+ return;
+ }
+
+ gchar* name;
+ gchar* jsapi;
+ gchar* entry_point;
+ GVariantIter *it;
+ GVariantIter* entry_it;
+
+ g_variant_get(value, "(a(ssas))", &it);
+ while (g_variant_iter_loop(it, "(ssas)", &name, &jsapi, &entry_it)) {
+ ExtensionCodePoints* code = new ExtensionCodePoints;
+ code->api = std::string(jsapi);
+ while (g_variant_iter_loop(entry_it, "s", &entry_point)) {
+ code->entry_points.push_back(std::string(entry_point));
+ }
+ extension_apis_.insert(std::make_pair(std::string(name), code));
+ }
+}
+
+void ExtensionClient::HandleSignal(
+ const std::string& signal_name, GVariant* parameters) {
+ if (signal_name == kSignalOnMessageToJS) {
+ gchar* instance_id;
+ gchar* msg;
+ g_variant_get(parameters, "(&s&s)", &instance_id, &msg);
+ auto it = handlers_.find(instance_id);
+ if (it != handlers_.end()) {
+ InstanceHandler* handler = it->second;
+ if (handler) {
+ handler->HandleMessageFromNative(msg);
+ }
+ }
+ }
+}
+
+} // namespace wrt
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WRT_BUNDLE_EXTENSION_CLIENT_H_
+#define WRT_BUNDLE_EXTENSION_CLIENT_H_
+
+#include <string>
+#include <memory>
+#include <map>
+#include <vector>
+
+#include "common/dbus_client.h"
+
+namespace wrt {
+
+class ExtensionClient {
+ public:
+ struct InstanceHandler {
+ virtual void HandleMessageFromNative(const std::string& msg) = 0;
+ protected:
+ ~InstanceHandler() {}
+ };
+
+ ExtensionClient();
+ virtual ~ExtensionClient();
+
+ std::string CreateInstance(const std::string& extension_name,
+ InstanceHandler* handler);
+ void DestroyInstance(const std::string& instance_id);
+
+ void PostMessageToNative(const std::string& instance_id,
+ const std::string& msg);
+ std::string SendSyncMessageToNative(const std::string& instance_id,
+ const std::string& msg);
+
+ void Initialize(const std::string& uuid);
+
+ struct ExtensionCodePoints {
+ std::string api;
+ std::vector<std::string> entry_points;
+ };
+
+ typedef std::map<std::string, ExtensionCodePoints*> ExtensionAPIMap;
+ const ExtensionAPIMap& extension_apis() const { return extension_apis_; }
+
+ private:
+ void HandleSignal(const std::string& signal_name, GVariant* parameters);
+
+ ExtensionAPIMap extension_apis_;
+ std::map<std::string, InstanceHandler*> handlers_;
+ DBusClient dbus_extension_client_;
+};
+
+} // namespace wrt
+
+#endif // WRT_BUNDLE_EXTENSION_CLIENT_H_
--- /dev/null
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <iostream>
+
+#include "bundle/extension_client.h"
+
+using namespace std;
+using namespace wrt;
+
+int main(int argc, char* argv[]) {
+
+ if (argc < 2) {
+ fprintf(stderr, "uuid is requried.\n");
+ }
+
+ ExtensionClient extension_client;
+
+ extension_client.Initialize(argv[1]);
+
+ string instance_id = extension_client.CreateInstance("tizen", NULL);
+ extension_client.DestroyInstance(instance_id);
+ cout << instance_id << endl;
+
+ return 0;
+}
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bundle/extension_module.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <v8/v8.h>
+
+#include <vector>
+
+#include "common/logger.h"
+#include "bundle/extension_client.h"
+#include "bundle/module_system.h"
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example. If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function. In these rare
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is
+// due to a limitation in C++'s template system. The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+namespace wrt {
+
+namespace {
+
+// This is the key used in the data object passed to our callbacks to store a
+// pointer back to kWrtExtensionModule.
+const char* kWrtExtensionModule = "kWrtExtensionModule";
+
+} // namespace
+
+ExtensionModule::ExtensionModule(ExtensionClient* client,
+ ModuleSystem* module_system,
+ const std::string& extension_name,
+ const std::string& extension_code)
+ : extension_name_(extension_name),
+ extension_code_(extension_code),
+ client_(client),
+ module_system_(module_system) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::Object> function_data = v8::Object::New(isolate);
+ function_data->Set(v8::String::NewFromUtf8(isolate, kWrtExtensionModule),
+ v8::External::New(isolate, this));
+
+ v8::Handle<v8::ObjectTemplate> object_template =
+ v8::ObjectTemplate::New(isolate);
+ // TODO(cmarcelo): Use Template::Set() function that takes isolate, once we
+ // update the Chromium (and V8) version.
+ object_template->Set(
+ v8::String::NewFromUtf8(isolate, "postMessage"),
+ v8::FunctionTemplate::New(isolate, PostMessageCallback, function_data));
+ object_template->Set(
+ v8::String::NewFromUtf8(isolate, "sendSyncMessage"),
+ v8::FunctionTemplate::New(
+ isolate, SendSyncMessageCallback, function_data));
+ object_template->Set(
+ v8::String::NewFromUtf8(isolate, "setMessageListener"),
+ v8::FunctionTemplate::New(
+ isolate, SetMessageListenerCallback, function_data));
+
+ function_data_.Reset(isolate, function_data);
+ object_template_.Reset(isolate, object_template);
+}
+
+ExtensionModule::~ExtensionModule() {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+
+ // Deleting the data will disable the functions, they'll return early. We do
+ // this because it might be the case that the JS objects we created outlive
+ // this object (getting references from inside an iframe and then destroying
+ // the iframe), even if we destroy the references we have.
+ v8::Handle<v8::Object> function_data =
+ v8::Local<v8::Object>::New(isolate, function_data_);
+ function_data->Delete(v8::String::NewFromUtf8(isolate,
+ kWrtExtensionModule));
+
+ object_template_.Reset();
+ function_data_.Reset();
+ message_listener_.Reset();
+
+ if (!instance_id_.empty())
+ client_->DestroyInstance(instance_id_);
+}
+
+namespace {
+
+std::string CodeToEnsureNamespace(const std::string& extension_name) {
+ std::string result;
+ size_t pos = 0;
+ while (true) {
+ pos = extension_name.find('.', pos);
+ if (pos == std::string::npos) {
+ result += extension_name + " = {};";
+ break;
+ }
+ std::string ns = extension_name.substr(0, pos);
+ result += ns + " = " + ns + " || {}; ";
+ pos++;
+ }
+ return result;
+}
+
+// Templatized backend for StringPrintF/StringAppendF. This does not finalize
+// the va_list, the caller is expected to do that.
+template <class StringType>
+static void StringAppendVT(StringType* dst,
+ const typename StringType::value_type* format,
+ va_list ap) {
+ // First try with a small fixed size buffer.
+ // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
+ // and StringUtilTest.StringPrintfBounds.
+ typename StringType::value_type stack_buf[1024];
+
+ va_list ap_copy;
+ va_copy(ap_copy, ap);
+
+ int result = vsnprintf(stack_buf, arraysize(stack_buf), format, ap_copy);
+ va_end(ap_copy);
+
+ if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
+ // It fit.
+ dst->append(stack_buf, result);
+ return;
+ }
+
+ // Repeatedly increase buffer size until it fits.
+ int mem_length = arraysize(stack_buf);
+ while (true) {
+ if (result < 0) {
+ if (errno != 0 && errno != EOVERFLOW)
+ return;
+ // Try doubling the buffer size.
+ mem_length *= 2;
+ } else {
+ // We need exactly "result + 1" characters.
+ mem_length = result + 1;
+ }
+
+ if (mem_length > 32 * 1024 * 1024) {
+ // That should be plenty, don't try anything larger. This protects
+ // against huge allocations when using vsnprintfT implementations that
+ // return -1 for reasons other than overflow without setting errno.
+ LOGE("Unable to printf the requested string due to size.");
+ return;
+ }
+
+ std::vector<typename StringType::value_type> mem_buf(mem_length);
+
+ // NOTE: You can only use a va_list once. Since we're in a while loop, we
+ // need to make a new copy each time so we don't use up the original.
+ va_copy(ap_copy, ap);
+ result = vsnprintf(&mem_buf[0], mem_length, format, ap_copy);
+ va_end(ap_copy);
+
+ if ((result >= 0) && (result < mem_length)) {
+ // It fit.
+ dst->append(&mem_buf[0], result);
+ return;
+ }
+ }
+}
+
+std::string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::string result;
+ StringAppendVT(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+// Wrap API code into a callable form that takes extension object as parameter.
+std::string WrapAPICode(const std::string& extension_code,
+ const std::string& extension_name) {
+ // We take care here to make sure that line numbering for api_code after
+ // wrapping doesn't change, so that syntax errors point to the correct line.
+
+ return StringPrintf(
+ "var %s; (function(extension, requireNative) { "
+ "extension.internal = {};"
+ "extension.internal.sendSyncMessage = extension.sendSyncMessage;"
+ "delete extension.sendSyncMessage;"
+ "var exports = {}; (function() {'use strict'; %s\n})();"
+ "%s = exports; });",
+ CodeToEnsureNamespace(extension_name).c_str(),
+ extension_code.c_str(),
+ extension_name.c_str());
+}
+
+std::string ExceptionToString(const v8::TryCatch& try_catch) {
+ std::string str;
+ v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
+ v8::String::Utf8Value exception(try_catch.Exception());
+ v8::Local<v8::Message> message(try_catch.Message());
+ if (message.IsEmpty()) {
+ str.append(StringPrintf("%s\n", *exception));
+ } else {
+ v8::String::Utf8Value filename(message->GetScriptResourceName());
+ int linenum = message->GetLineNumber();
+ int colnum = message->GetStartColumn();
+ str.append(StringPrintf(
+ "%s:%i:%i %s\n", *filename, linenum, colnum, *exception));
+ v8::String::Utf8Value sourceline(message->GetSourceLine());
+ str.append(StringPrintf("%s\n", *sourceline));
+ }
+ return str;
+}
+
+v8::Handle<v8::Value> RunString(const std::string& code,
+ std::string* exception) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope handle_scope(isolate);
+ v8::Handle<v8::String> v8_code(
+ v8::String::NewFromUtf8(isolate, code.c_str()));
+
+ v8::TryCatch try_catch;
+ try_catch.SetVerbose(true);
+
+ v8::Handle<v8::Script> script(v8::Script::Compile(v8_code));
+ if (try_catch.HasCaught()) {
+ *exception = ExceptionToString(try_catch);
+ return handle_scope.Escape(
+ v8::Local<v8::Primitive>(v8::Undefined(isolate)));
+ }
+
+ v8::Local<v8::Value> result = script->Run();
+ if (try_catch.HasCaught()) {
+ *exception = ExceptionToString(try_catch);
+ return handle_scope.Escape(
+ v8::Local<v8::Primitive>(v8::Undefined(isolate)));
+ }
+
+ return handle_scope.Escape(result);
+}
+
+} // namespace
+
+void ExtensionModule::LoadExtensionCode(v8::Handle<v8::Context> context) {
+ instance_id_ = client_->CreateInstance(extension_name_, this);
+
+ std::string exception;
+ std::string wrapped_api_code = WrapAPICode(extension_code_, extension_name_);
+ v8::Handle<v8::Value> result = RunString(wrapped_api_code, &exception);
+
+ if (!result->IsFunction()) {
+ LoggerE("Couldn't load JS API code for %s: %s",
+ extension_name_.c_str(), exception.c_str());
+ return;
+ }
+ v8::Handle<v8::Function> callable_api_code =
+ v8::Handle<v8::Function>::Cast(result);
+ v8::Handle<v8::ObjectTemplate> object_template =
+ v8::Local<v8::ObjectTemplate>::New(context->GetIsolate(),
+ object_template_);
+
+ const int argc = 1;
+ v8::Handle<v8::Value> argv[argc] = {
+ object_template->NewInstance()
+ };
+
+ v8::TryCatch try_catch;
+ try_catch.SetVerbose(true);
+ callable_api_code->Call(context->Global(), argc, argv);
+ if (try_catch.HasCaught()) {
+ LoggerE("Exception while loading JS API code for %s: %s",
+ extension_name_.c_str(), ExceptionToString(try_catch).c_str());
+ }
+}
+
+void ExtensionModule::HandleMessageFromNative(const std::string& msg) {
+ if (message_listener_.IsEmpty())
+ return;
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::Context> context = module_system_->GetV8Context();
+ v8::Context::Scope context_scope(context);
+
+ v8::Handle<v8::Value> args[] = {
+ v8::String::NewFromUtf8(isolate, msg.c_str()) };
+
+ v8::Handle<v8::Function> message_listener =
+ v8::Local<v8::Function>::New(isolate, message_listener_);
+
+ v8::TryCatch try_catch;
+ message_listener->Call(context->Global(), 1, args);
+ if (try_catch.HasCaught())
+ LoggerE("Exception when running message listener: %s",
+ ExceptionToString(try_catch).c_str());
+}
+
+// static
+void ExtensionModule::PostMessageCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::ReturnValue<v8::Value> result(info.GetReturnValue());
+ ExtensionModule* module = GetExtensionModule(info);
+ if (!module || info.Length() != 1) {
+ result.Set(false);
+ return;
+ }
+
+ v8::Handle<v8::Context> context = info.GetIsolate()->GetCurrentContext();
+ v8::String::Utf8Value value(info[0]->ToString());
+
+ // CHECK(module->instance_id_);
+ module->client_->PostMessageToNative(module->instance_id_,
+ std::string(*value));
+ result.Set(true);
+}
+
+// static
+void ExtensionModule::SendSyncMessageCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::ReturnValue<v8::Value> result(info.GetReturnValue());
+ ExtensionModule* module = GetExtensionModule(info);
+ if (!module || info.Length() != 1) {
+ result.Set(false);
+ return;
+ }
+
+ v8::Handle<v8::Context> context = info.GetIsolate()->GetCurrentContext();
+ v8::String::Utf8Value value(info[0]->ToString());
+
+ // CHECK(module->instance_id_);
+ std::string reply =
+ module->client_->SendSyncMessageToNative(module->instance_id_,
+ std::string(*value));
+
+ // If we tried to send a message to an instance that became invalid,
+ // then reply will be NULL.
+ if (!reply.empty()) {
+ result.Set(v8::String::NewFromUtf8(info.GetIsolate(), reply.c_str()));
+ }
+}
+
+// static
+void ExtensionModule::SetMessageListenerCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::ReturnValue<v8::Value> result(info.GetReturnValue());
+ ExtensionModule* module = GetExtensionModule(info);
+ if (!module || info.Length() != 1) {
+ result.Set(false);
+ return;
+ }
+
+ if (!info[0]->IsFunction() && !info[0]->IsUndefined()) {
+ LoggerE("Trying to set message listener with invalid value.");
+ result.Set(false);
+ return;
+ }
+
+ v8::Isolate* isolate = info.GetIsolate();
+ if (info[0]->IsUndefined())
+ module->message_listener_.Reset();
+ else
+ module->message_listener_.Reset(isolate, info[0].As<v8::Function>());
+
+ result.Set(true);
+}
+
+// static
+ExtensionModule* ExtensionModule::GetExtensionModule(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Object> data = info.Data().As<v8::Object>();
+ v8::Local<v8::Value> module =
+ data->Get(v8::String::NewFromUtf8(isolate, kWrtExtensionModule));
+ if (module.IsEmpty() || module->IsUndefined()) {
+ LoggerE("Trying to use extension from already destroyed context!");
+ return NULL;
+ }
+ // CHECK(module->IsExternal());
+ return static_cast<ExtensionModule*>(module.As<v8::External>()->Value());
+}
+
+} // namespace wrt
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WRT_BUNDLE_EXTENSION_MODULE_H_
+#define WRT_BUNDLE_EXTENSION_MODULE_H_
+
+#include <v8/v8.h>
+
+#include <memory>
+#include <string>
+
+#include "bundle/extension_client.h"
+
+namespace wrt {
+
+class ModuleSystem;
+
+// Responsible for running the JS code of a Extension. This includes
+// creating and exposing an 'extension' object for the execution context of
+// the extension JS code.
+//
+// We'll create one ExtensionModule per extension/frame pair, so
+// there'll be a set of different modules per v8::Context.
+class ExtensionModule : public ExtensionClient::InstanceHandler {
+ public:
+ ExtensionModule(ExtensionClient* client,
+ ModuleSystem* module_system,
+ const std::string& extension_name,
+ const std::string& extension_code);
+ virtual ~ExtensionModule();
+
+ // TODO(cmarcelo): Make this return a v8::Handle<v8::Object>, and
+ // let the module system set it to the appropriated object.
+ void LoadExtensionCode(v8::Handle<v8::Context> context);
+
+ std::string extension_name() const { return extension_name_; }
+
+ private:
+ // ExtensionClient::InstanceHandler implementation.
+ virtual void HandleMessageFromNative(const std::string& msg);
+
+ // Callbacks for JS functions available in 'extension' object.
+ static void PostMessageCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+ static void SendSyncMessageCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+ static void SetMessageListenerCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+
+ static ExtensionModule* GetExtensionModule(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+
+ // Template for the 'extension' object exposed to the extension JS code.
+ v8::Persistent<v8::ObjectTemplate> object_template_;
+
+ // This JS object contains a pointer back to the ExtensionModule, it is
+ // set as data for the function callbacks.
+ v8::Persistent<v8::Object> function_data_;
+
+ // Function to be called when the extension sends a message to its JS code.
+ // This value is registered by using 'extension.setMessageListener()'.
+ v8::Persistent<v8::Function> message_listener_;
+
+ std::string extension_name_;
+ std::string extension_code_;
+
+ ExtensionClient* client_;
+ ModuleSystem* module_system_;
+ std::string instance_id_;
+};
+
+} // namespace wrt
+
+#endif // WRT_BUNDLE_EXTENSION_MODULE_H_
--- /dev/null
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bundle/extension_renderer_controller.h"
+
+#include <v8/v8.h>
+#include <string>
+#include <utility>
+
+#include "common/logger.h"
+#include "bundle/extension_client.h"
+#include "bundle/extension_module.h"
+#include "bundle/module_system.h"
+
+namespace wrt {
+
+namespace {
+
+void CreateExtensionModules(ExtensionClient* client,
+ ModuleSystem* module_system) {
+ const ExtensionClient::ExtensionAPIMap& extensions =
+ client->extension_apis();
+ auto it = extensions.begin();
+ for (; it != extensions.end(); ++it) {
+ ExtensionClient::ExtensionCodePoints* codepoint = it->second;
+ if (codepoint->api.empty())
+ continue;
+
+ std::unique_ptr<ExtensionModule> module(
+ new ExtensionModule(client, module_system, it->first, codepoint->api));
+ module_system->RegisterExtensionModule(
+ std::move(module), codepoint->entry_points);
+ }
+}
+
+} // namespace
+
+ExtensionRendererController& ExtensionRendererController::GetInstance() {
+ static ExtensionRendererController instance;
+ return instance;
+}
+
+ExtensionRendererController::ExtensionRendererController()
+ : extensions_client_(new ExtensionClient()) {
+}
+
+ExtensionRendererController::~ExtensionRendererController() {
+}
+
+void ExtensionRendererController::DidCreateScriptContext(
+ v8::Handle<v8::Context> context) {
+ ModuleSystem* module_system = new ModuleSystem(context);
+ ModuleSystem::SetModuleSystemInContext(
+ std::unique_ptr<ModuleSystem>(module_system), context);
+
+ CreateExtensionModules(extensions_client_.get(), module_system);
+ module_system->Initialize();
+}
+
+void ExtensionRendererController::WillReleaseScriptContext(
+ v8::Handle<v8::Context> context) {
+ v8::Context::Scope contextScope(context);
+ ModuleSystem::ResetModuleSystemFromContext(context);
+}
+
+void ExtensionRendererController::InitializeExtensions(
+ const std::string& uuid) {
+ extensions_client_->Initialize(uuid);
+}
+
+} // namespace wrt
// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+
+#ifndef WRT_BUNDLE_EXTENSION_RENDERER_CONTROLLER_H_
+#define WRT_BUNDLE_EXTENSION_RENDERER_CONTROLLER_H_
+
+#include <v8/v8.h>
+#include <string>
+#include <memory>
+
+namespace wrt {
+
+class ExtensionClient;
+
+class ExtensionRendererController {
+ public:
+ static ExtensionRendererController& GetInstance();
+
+ void DidCreateScriptContext(v8::Handle<v8::Context> context);
+ void WillReleaseScriptContext(v8::Handle<v8::Context> context);
+
+ void InitializeExtensions(const std::string& uuid);
+
+ private:
+ ExtensionRendererController();
+ virtual ~ExtensionRendererController();
+
+ private:
+ std::unique_ptr<ExtensionClient> extensions_client_;
+};
+
+} // namespace wrt
+
+#endif // WRT_BUNDLE_EXTENSION_RENDERER_CONTROLLER_H_
#include <string>
#include "common/logger.h"
+#include "bundle/extension_renderer_controller.h"
extern "C" void DynamicSetWidgetInfo(int widget_id) {
LoggerD("InjectedBundle::DynamicSetWidgetInfo !!");
const char* theme,
const char* base_url) {
LoggerD("InjectedBundle::DynamicPluginStartSession !!");
+
+ wrt::ExtensionRendererController& controller =
+ wrt::ExtensionRendererController::GetInstance();
+ // TODO(wy80.choi): Temporarily, uuid is passed as theme arguments.
+ controller.InitializeExtensions(theme);
+ controller.DidCreateScriptContext(context);
}
extern "C" void DynamicPluginStopSession(
int widget_id, v8::Handle<v8::Context> context) {
LoggerD("InjectedBundle::DynamicPluginStopSession !!");
+
+ wrt::ExtensionRendererController& controller =
+ wrt::ExtensionRendererController::GetInstance();
+ controller.WillReleaseScriptContext(context);
}
extern "C" void DynamicUrlParsing(
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bundle/module_system.h"
+
+#include <v8/v8.h>
+#include <algorithm>
+
+#include "common/logger.h"
+#include "bundle/extension_module.h"
+
+namespace wrt {
+
+namespace {
+
+// Index used to set embedder data into v8::Context, so we can get from a
+// context to its corresponding module. Index chosen to not conflict with
+// WebCore::V8ContextEmbedderDataField in V8PerContextData.h.
+const int kModuleSystemEmbedderDataIndex = 8;
+
+// This is the key used in the data object passed to our callbacks to store a
+// pointer back to XWalkExtensionModule.
+const char* kWrtModuleSystem = "kWrtModuleSystem";
+
+ModuleSystem* GetModuleSystem(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Handle<v8::Object> data = info.Data().As<v8::Object>();
+ v8::Handle<v8::Value> module_system =
+ data->Get(v8::String::NewFromUtf8(isolate, kWrtModuleSystem));
+ if (module_system.IsEmpty() || module_system->IsUndefined()) {
+ LoggerE("ModuleSystem is not defined.");
+ return NULL;
+ }
+
+ return static_cast<ModuleSystem*>(
+ module_system.As<v8::External>()->Value());
+}
+
+} // namespace
+
+ModuleSystem::ModuleSystem(v8::Handle<v8::Context> context) {
+ v8::Isolate* isolate = context->GetIsolate();
+ v8_context_.Reset(isolate, context);
+
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::Object> function_data = v8::Object::New(isolate);
+ function_data->Set(v8::String::NewFromUtf8(isolate, kWrtModuleSystem),
+ v8::External::New(isolate, this));
+
+ function_data_.Reset(isolate, function_data);
+}
+
+ModuleSystem::~ModuleSystem() {
+ DeleteExtensionModules();
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+
+ function_data_.Reset();
+ v8_context_.Reset();
+}
+
+// static
+ModuleSystem* ModuleSystem::GetModuleSystemFromContext(
+ v8::Handle<v8::Context> context) {
+ return reinterpret_cast<ModuleSystem*>(
+ context->GetAlignedPointerFromEmbedderData(
+ kModuleSystemEmbedderDataIndex));
+}
+
+// static
+void ModuleSystem::SetModuleSystemInContext(
+ std::unique_ptr<ModuleSystem> module_system,
+ v8::Handle<v8::Context> context) {
+ context->SetAlignedPointerInEmbedderData(kModuleSystemEmbedderDataIndex,
+ module_system.release());
+}
+
+// static
+void ModuleSystem::ResetModuleSystemFromContext(
+ v8::Handle<v8::Context> context) {
+ delete GetModuleSystemFromContext(context);
+ SetModuleSystemInContext(std::unique_ptr<ModuleSystem>(), context);
+}
+
+void ModuleSystem::RegisterExtensionModule(
+ std::unique_ptr<ExtensionModule> module,
+ const std::vector<std::string>& entry_points) {
+ const std::string& extension_name = module->extension_name();
+ if (ContainsEntryPoint(extension_name)) {
+ LoggerE("Can't register Extension Module named for extension "
+ "'%s' in the Module System because name was already registered.",
+ extension_name.c_str());
+ return;
+ }
+
+ std::vector<std::string>::const_iterator it = entry_points.begin();
+ for (; it != entry_points.end(); ++it) {
+ if (ContainsEntryPoint(*it)) {
+ LoggerE("Can't register Extension Module named for extension "
+ "'%s' in the Module System because another extension "
+ "has the entry point '%s'.",
+ extension_name.c_str(), (*it).c_str());
+ return;
+ }
+ }
+
+ extension_modules_.push_back(
+ ExtensionModuleEntry(extension_name, module.release(), entry_points));
+}
+
+namespace {
+
+v8::Handle<v8::Value> EnsureTargetObjectForTrampoline(
+ v8::Handle<v8::Context> context, const std::vector<std::string>& path,
+ std::string* error) {
+ v8::Handle<v8::Object> object = context->Global();
+ v8::Isolate* isolate = context->GetIsolate();
+
+ std::vector<std::string>::const_iterator it = path.begin();
+ for (; it != path.end(); ++it) {
+ v8::Handle<v8::String> part =
+ v8::String::NewFromUtf8(isolate, it->c_str());
+ v8::Handle<v8::Value> value = object->Get(part);
+
+ if (value->IsUndefined()) {
+ v8::Handle<v8::Object> next_object = v8::Object::New(isolate);
+ object->Set(part, next_object);
+ object = next_object;
+ continue;
+ }
+
+ if (!value->IsObject()) {
+ *error = "the property '" + *it + "' in the path is undefined";
+ return v8::Undefined(isolate);
+ }
+
+ object = value.As<v8::Object>();
+ }
+ return object;
+}
+
+v8::Handle<v8::Value> GetObjectForPath(v8::Handle<v8::Context> context,
+ const std::vector<std::string>& path,
+ std::string* error) {
+ v8::Handle<v8::Object> object = context->Global();
+ v8::Isolate* isolate = context->GetIsolate();
+
+ std::vector<std::string>::const_iterator it = path.begin();
+ for (; it != path.end(); ++it) {
+ v8::Handle<v8::String> part =
+ v8::String::NewFromUtf8(isolate, it->c_str());
+ v8::Handle<v8::Value> value = object->Get(part);
+
+ if (!value->IsObject()) {
+ *error = "the property '" + *it + "' in the path is undefined";
+ return v8::Undefined(isolate);
+ }
+
+ object = value.As<v8::Object>();
+ }
+ return object;
+}
+
+} // namespace
+
+template <typename STR>
+void SplitString(const STR& str, const typename STR::value_type s,
+ std::vector<STR>* r) {
+ r->clear();
+ size_t last = 0;
+ size_t c = str.size();
+ for (size_t i = 0; i <= c; ++i) {
+ if (i == c || str[i] == s) {
+ STR tmp(str, last, i - last);
+ if (i != c || !r->empty() || !tmp.empty())
+ r->push_back(tmp);
+ last = i + 1;
+ }
+ }
+}
+
+bool ModuleSystem::SetTrampolineAccessorForEntryPoint(
+ v8::Handle<v8::Context> context,
+ const std::string& entry_point,
+ v8::Local<v8::External> user_data) {
+ std::vector<std::string> path;
+ SplitString(entry_point, '.', &path);
+ std::string basename = path.back();
+ path.pop_back();
+
+ std::string error;
+ v8::Handle<v8::Value> value =
+ EnsureTargetObjectForTrampoline(context, path, &error);
+ if (value->IsUndefined()) {
+ LoggerE("Error installing trampoline for %s: %s.",
+ entry_point.c_str(), error.c_str());
+ return false;
+ }
+
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::Local<v8::Array> params = v8::Array::New(isolate);
+ v8::Local<v8::String> entry =
+ v8::String::NewFromUtf8(isolate, entry_point.c_str());
+ params->Set(v8::Integer::New(isolate, 0), user_data);
+ params->Set(v8::Integer::New(isolate, 1), entry);
+
+ // FIXME(cmarcelo): ensure that trampoline is readonly.
+ value.As<v8::Object>()->SetAccessor(
+ v8::String::NewFromUtf8(isolate, basename.c_str()),
+ TrampolineCallback, TrampolineSetterCallback, params);
+ return true;
+}
+
+// static
+bool ModuleSystem::DeleteAccessorForEntryPoint(
+ v8::Handle<v8::Context> context,
+ const std::string& entry_point) {
+ std::vector<std::string> path;
+ SplitString(entry_point, '.', &path);
+ std::string basename = path.back();
+ path.pop_back();
+
+ std::string error;
+ v8::Handle<v8::Value> value = GetObjectForPath(context, path, &error);
+ if (value->IsUndefined()) {
+ LoggerE("Error retrieving object for %s: %s.",
+ entry_point.c_str(), error.c_str());
+ return false;
+ }
+
+ value.As<v8::Object>()->ForceDelete(
+ v8::String::NewFromUtf8(context->GetIsolate(), basename.c_str()));
+ return true;
+}
+
+bool ModuleSystem::InstallTrampoline(v8::Handle<v8::Context> context,
+ ExtensionModuleEntry* entry) {
+ v8::Local<v8::External> entry_ptr =
+ v8::External::New(context->GetIsolate(), entry);
+ bool ret = SetTrampolineAccessorForEntryPoint(context, entry->name,
+ entry_ptr);
+ if (!ret) {
+ LoggerE("Error installing trampoline for '%s'.", entry->name.c_str());
+ return false;
+ }
+
+ auto it = entry->entry_points.begin();
+ for (; it != entry->entry_points.end(); ++it) {
+ ret = SetTrampolineAccessorForEntryPoint(context, *it, entry_ptr);
+ if (!ret) {
+ // TODO(vcgomes): Remove already added trampolines when it fails.
+ LoggerE("Error installing trampoline for '%s'.", entry->name.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+void ModuleSystem::Initialize() {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::Context> context = GetV8Context();
+
+ MarkModulesWithTrampoline();
+
+ auto it = extension_modules_.begin();
+ for (; it != extension_modules_.end(); ++it) {
+ if (it->use_trampoline && InstallTrampoline(context, &*it))
+ continue;
+ it->module->LoadExtensionCode(context);
+ EnsureExtensionNamespaceIsReadOnly(context, it->name);
+ }
+}
+
+v8::Handle<v8::Context> ModuleSystem::GetV8Context() {
+ return v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), v8_context_);
+}
+
+bool ModuleSystem::ContainsEntryPoint(
+ const std::string& entry) {
+ auto it = extension_modules_.begin();
+ for (; it != extension_modules_.end(); ++it) {
+ if (it->name == entry)
+ return true;
+
+ auto entry_it = std::find(
+ it->entry_points.begin(), it->entry_points.end(), entry);
+ if (entry_it != it->entry_points.end()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ModuleSystem::DeleteExtensionModules() {
+ for (ExtensionModules::iterator it = extension_modules_.begin();
+ it != extension_modules_.end(); ++it) {
+ delete it->module;
+ }
+ extension_modules_.clear();
+}
+
+// static
+void ModuleSystem::LoadExtensionForTrampoline(
+ v8::Isolate* isolate,
+ v8::Local<v8::Value> data) {
+ v8::Local<v8::Array> params = data.As<v8::Array>();
+ void* ptr = params->Get(
+ v8::Integer::New(isolate, 0)).As<v8::External>()->Value();
+
+ ExtensionModuleEntry* entry = static_cast<ExtensionModuleEntry*>(ptr);
+
+ if (!entry)
+ return;
+
+ v8::Handle<v8::Context> context = isolate->GetCurrentContext();
+
+ DeleteAccessorForEntryPoint(context, entry->name);
+
+ auto it = entry->entry_points.begin();
+ for (; it != entry->entry_points.end(); ++it) {
+ DeleteAccessorForEntryPoint(context, *it);
+ }
+
+ ModuleSystem* module_system = GetModuleSystemFromContext(context);
+
+ ExtensionModule* module = entry->module;
+ module->LoadExtensionCode(module_system->GetV8Context());
+
+ module_system->EnsureExtensionNamespaceIsReadOnly(context, entry->name);
+}
+
+// static
+v8::Handle<v8::Value> ModuleSystem::RefetchHolder(
+ v8::Isolate* isolate,
+ v8::Local<v8::Value> data) {
+ v8::Local<v8::Array> params = data.As<v8::Array>();
+ const std::string entry_point = *v8::String::Utf8Value(
+ params->Get(v8::Integer::New(isolate, 1)).As<v8::String>());
+
+ std::vector<std::string> path;
+ SplitString(entry_point, '.', &path);
+ path.pop_back();
+
+ std::string error;
+ return GetObjectForPath(isolate->GetCurrentContext(), path, &error);
+}
+
+// static
+void ModuleSystem::TrampolineCallback(
+ v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ ModuleSystem::LoadExtensionForTrampoline(info.GetIsolate(), info.Data());
+ v8::Handle<v8::Value> holder = RefetchHolder(info.GetIsolate(), info.Data());
+ if (holder->IsUndefined())
+ return;
+
+ info.GetReturnValue().Set(holder.As<v8::Object>()->Get(property));
+}
+
+// static
+void ModuleSystem::TrampolineSetterCallback(
+ v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<void>& info) {
+ ModuleSystem::LoadExtensionForTrampoline(info.GetIsolate(), info.Data());
+ v8::Handle<v8::Value> holder = RefetchHolder(info.GetIsolate(), info.Data());
+ if (holder->IsUndefined())
+ return;
+
+ holder.As<v8::Object>()->Set(property, value);
+}
+
+ModuleSystem::ExtensionModuleEntry::ExtensionModuleEntry(
+ const std::string& name,
+ ExtensionModule* module,
+ const std::vector<std::string>& entry_points) :
+ name(name), module(module), use_trampoline(true),
+ entry_points(entry_points) {
+}
+
+ModuleSystem::ExtensionModuleEntry::~ExtensionModuleEntry() {
+}
+
+// Returns whether the name of first is prefix of the second, considering "."
+// character as a separator. So "a" is prefix of "a.b" but not of "ab".
+bool ModuleSystem::ExtensionModuleEntry::IsPrefix(
+ const ExtensionModuleEntry& first,
+ const ExtensionModuleEntry& second) {
+ const std::string& p = first.name;
+ const std::string& s = second.name;
+ return s.size() > p.size() && s[p.size()] == '.'
+ && std::mismatch(p.begin(), p.end(), s.begin()).first == p.end();
+}
+
+// Mark the extension modules that we want to setup "trampolines"
+// instead of loading the code directly. The current algorithm is very
+// simple: we only create trampolines for extensions that are leaves
+// in the namespace tree.
+//
+// For example, if there are two extensions "tizen" and "tizen.time",
+// the first one won't be marked with trampoline, but the second one
+// will. So we'll only load code for "tizen" extension.
+void ModuleSystem::MarkModulesWithTrampoline() {
+ std::sort(extension_modules_.begin(), extension_modules_.end());
+
+ ExtensionModules::iterator it = extension_modules_.begin();
+ while (it != extension_modules_.end()) {
+ it = std::adjacent_find(it, extension_modules_.end(),
+ &ExtensionModuleEntry::IsPrefix);
+ if (it == extension_modules_.end())
+ break;
+ it->use_trampoline = false;
+ ++it;
+ }
+}
+
+void ModuleSystem::EnsureExtensionNamespaceIsReadOnly(
+ v8::Handle<v8::Context> context,
+ const std::string& extension_name) {
+ std::vector<std::string> path;
+ SplitString(extension_name, '.', &path);
+ std::string basename = path.back();
+ path.pop_back();
+
+ std::string error;
+ v8::Handle<v8::Value> value = GetObjectForPath(context, path, &error);
+ if (value->IsUndefined()) {
+ LoggerE("Error retrieving object for %s: %s.",
+ extension_name.c_str(), error.c_str());
+ return;
+ }
+
+ v8::Handle<v8::String> v8_extension_name(
+ v8::String::NewFromUtf8(context->GetIsolate(), basename.c_str()));
+ value.As<v8::Object>()->ForceSet(
+ v8_extension_name, value.As<v8::Object>()->Get(v8_extension_name),
+ v8::ReadOnly);
+}
+
+} // namespace wrt
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WRT_BUNDLE_MODULE_SYSTEM_H_
+#define WRT_BUNDLE_MODULE_SYSTEM_H_
+
+#include <v8/v8.h>
+#include <vector>
+#include <string>
+#include <memory>
+
+namespace wrt {
+
+class ExtensionModule;
+
+class ModuleSystem {
+ public:
+ explicit ModuleSystem(v8::Handle<v8::Context> context);
+ ~ModuleSystem();
+
+ static ModuleSystem* GetModuleSystemFromContext(
+ v8::Handle<v8::Context> context);
+ static void SetModuleSystemInContext(
+ std::unique_ptr<ModuleSystem> module_system,
+ v8::Handle<v8::Context> context);
+ static void ResetModuleSystemFromContext(v8::Handle<v8::Context> context);
+
+ void RegisterExtensionModule(std::unique_ptr<ExtensionModule> module,
+ const std::vector<std::string>& entry_points);
+
+ void Initialize();
+
+ v8::Handle<v8::Context> GetV8Context();
+
+ private:
+ struct ExtensionModuleEntry {
+ ExtensionModuleEntry(const std::string& name, ExtensionModule* module,
+ const std::vector<std::string>& entry_points);
+ ~ExtensionModuleEntry();
+ std::string name;
+ ExtensionModule* module;
+ bool use_trampoline;
+ std::vector<std::string> entry_points;
+ bool operator<(const ExtensionModuleEntry& other) const {
+ return name < other.name;
+ }
+
+ static bool IsPrefix(const ExtensionModuleEntry& first,
+ const ExtensionModuleEntry& second);
+ };
+
+ bool SetTrampolineAccessorForEntryPoint(
+ v8::Handle<v8::Context> context,
+ const std::string& entry_point,
+ v8::Local<v8::External> user_data);
+
+ static bool DeleteAccessorForEntryPoint(v8::Handle<v8::Context> context,
+ const std::string& entry_point);
+
+ bool InstallTrampoline(v8::Handle<v8::Context> context,
+ ExtensionModuleEntry* entry);
+
+ static void TrampolineCallback(
+ v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info);
+ static void TrampolineSetterCallback(
+ v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<void>& info);
+ static void LoadExtensionForTrampoline(
+ v8::Isolate* isolate,
+ v8::Local<v8::Value> data);
+ static v8::Handle<v8::Value> RefetchHolder(
+ v8::Isolate* isolate,
+ v8::Local<v8::Value> data);
+
+ bool ContainsEntryPoint(const std::string& entry_point);
+ void MarkModulesWithTrampoline();
+ void DeleteExtensionModules();
+
+ void EnsureExtensionNamespaceIsReadOnly(v8::Handle<v8::Context> context,
+ const std::string& extension_name);
+
+ typedef std::vector<ExtensionModuleEntry> ExtensionModules;
+ ExtensionModules extension_modules_;
+
+ v8::Persistent<v8::Object> function_data_;
+
+ // Points back to the current context, used when native wants to callback
+ // JavaScript. When WillReleaseScriptContext() is called, we dispose this
+ // persistent.
+ v8::Persistent<v8::Context> v8_context_;
+};
+
+} // namespace wrt
+
+#endif // WRT_BUNDLE_MODULE_SYSTEM_H_
${BASE_SRCDIR}/common/command_line.cc
${BASE_SRCDIR}/common/dbus_server.cc
${BASE_SRCDIR}/common/dbus_client.cc
+ ${BASE_SRCDIR}/common/profiler.cc
)
INCLUDE_DIRECTORIES(${TARGET_COMMON_STATIC_INCS})
const char kDBusNameForExtension[] = "Extension";
const char kDBusInterfaceNameForExtension[] = "org.tizen.wrt.Extension";
+const char kMethodGetExtensions[] = "GetExtensions";
+const char kMethodCreateInstance[] = "CreateInstance";
+const char kMethodDestroyInstance[] = "DestroyInstance";
+const char kMethodSendSyncMessage[] = "SendSyncMessage";
+const char kMethodPostMessage[] = "PostMessage";
+const char kSignalOnMessageToJS[] = "OnMessageToJS";
} // namespace wrt
extern const char kDBusNameForExtension[];
extern const char kDBusInterfaceNameForExtension[];
+extern const char kMethodGetExtensions[];
+extern const char kMethodCreateInstance[];
+extern const char kMethodDestroyInstance[];
+extern const char kMethodSendSyncMessage[];
+extern const char kMethodPostMessage[];
+extern const char kSignalOnMessageToJS[];
} // namespace wrt
namespace wrt {
+namespace {
+
+void OnSignalReceived(GDBusConnection* /*connection*/,
+ const gchar* /*sender_name*/,
+ const gchar* /*object_path*/,
+ const gchar* interface_name,
+ const gchar* signal_name,
+ GVariant* parameters,
+ gpointer user_data) {
+ DBusClient* self = reinterpret_cast<DBusClient*>(user_data);
+ auto callback = self->GetSignalCallback(interface_name);
+ if (callback) {
+ callback(signal_name, parameters);
+ }
+}
+
+} // namespace
+
DBusClient::DBusClient()
- : connection_(NULL) {
+ : connection_(NULL),
+ signal_subscription_id_(0) {
}
DBusClient::~DBusClient() {
if (connection_) {
+ g_dbus_connection_signal_unsubscribe(connection_, signal_subscription_id_);
g_dbus_connection_close_sync(connection_, NULL, NULL);
}
}
g_error_free(err);
return false;
}
+
+ signal_subscription_id_ = g_dbus_connection_signal_subscribe(
+ connection_, NULL, NULL, NULL, NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+ OnSignalReceived, this, NULL);
+
return true;
}
return reply;
}
+void DBusClient::SetSignalCallback(const std::string& iface,
+ SignalCallback func) {
+ signal_callbacks_[iface] = func;
+}
+
+DBusClient::SignalCallback
+DBusClient::GetSignalCallback(const std::string& iface) {
+ return signal_callbacks_[iface];
+}
+
} // namespace wrt
#include <gio/gio.h>
#include <string>
+#include <functional>
+#include <map>
namespace wrt {
class DBusClient {
public:
+ typedef std::function<void(const std::string& signal,
+ GVariant* parameters)> SignalCallback;
+
DBusClient();
virtual ~DBusClient();
GVariant* Call(const std::string& iface, const std::string& method,
GVariant* parameters, const GVariantType* reply_type);
+
+ void SetSignalCallback(const std::string& iface, SignalCallback func);
+ SignalCallback GetSignalCallback(const std::string& iface);
+
private:
GDBusConnection* connection_;
+ guint signal_subscription_id_;
+ std::map<std::string, SignalCallback> signal_callbacks_;
};
} // namespace wrt
namespace {
-static void OnMethodCall(GDBusConnection* /*connection*/,
+static void OnMethodCall(GDBusConnection* connection,
const gchar* /*sender*/,
const gchar* /*object_path*/,
const gchar* interface_name,
}
auto callback = self->GetMethodCallback(interface_name);
if (callback) {
- callback(method_name, parameters, invocation);
+ callback(connection, method_name, parameters, invocation);
}
}
-static GVariant* OnGetProperty(GDBusConnection* /*connection*/,
+static GVariant* OnGetProperty(GDBusConnection* connection,
const gchar* /*sender*/,
const gchar* /*object_path*/,
const gchar* interface_name,
GVariant* ret = NULL;
if (callback) {
- ret = callback(property_name);
+ ret = callback(connection, property_name);
}
return ret;
}
-static gboolean OnSetProperty(GDBusConnection* /*connection*/,
+static gboolean OnSetProperty(GDBusConnection* connection,
const gchar* /*sender*/,
const gchar* /*object_path*/,
const gchar* interface_name,
gboolean ret = FALSE;
if (callback) {
- if (callback(property_name, value)) {
+ if (callback(connection, property_name, value)) {
ret = TRUE;
}
}
}
}
+void DBusServer::SendSignal(GDBusConnection* connection,
+ const std::string& iface,
+ const std::string& signal_name,
+ GVariant* parameters) {
+ GError* err = NULL;
+ gboolean ret = g_dbus_connection_emit_signal(
+ connection, NULL, "/",
+ iface.c_str(), signal_name.c_str(),
+ parameters, &err);
+ if (!ret) {
+ LoggerE("Failed to emit signal : '%s.%s'",
+ iface.c_str(), signal_name.c_str());
+ g_error_free(err);
+ }
+}
+
void DBusServer::SetPeerCredentialsCallback(PeerCredentialsCallback func) {
peer_credentials_callback_ = func;
}
property_setters_[iface] = func;
}
-DBusServer::PeerCredentialsCallback DBusServer::GetPeerCredentialsCallback() const {
+DBusServer::PeerCredentialsCallback
+DBusServer::GetPeerCredentialsCallback() const {
return peer_credentials_callback_;
}
-DBusServer::MethodCallback DBusServer::GetMethodCallback(const std::string& iface) {
+DBusServer::MethodCallback
+DBusServer::GetMethodCallback(const std::string& iface) {
return method_callbacks_[iface];
}
-DBusServer::PropertySetter DBusServer::GetPropertySetter(const std::string& iface) {
+DBusServer::PropertySetter
+DBusServer::GetPropertySetter(const std::string& iface) {
return property_setters_[iface];
}
-DBusServer::PropertyGetter DBusServer::GetPropertyGetter(const std::string& iface) {
+DBusServer::PropertyGetter
+DBusServer::GetPropertyGetter(const std::string& iface) {
return property_getters_[iface];
}
class DBusServer {
public:
typedef std::function<bool(GCredentials* creds)> PeerCredentialsCallback;
- typedef std::function<void(const std::string& method_name,
+ typedef std::function<void(GDBusConnection* connection,
+ const std::string& method_name,
GVariant* parameters,
GDBusMethodInvocation* invocation)> MethodCallback;
- typedef std::function<GVariant*(const gchar*)> PropertyGetter;
- typedef std::function<bool(const gchar*, GVariant*)> PropertySetter;
+ typedef std::function<GVariant*(GDBusConnection* connection,
+ const gchar* property)> PropertyGetter;
+ typedef std::function<bool(GDBusConnection* connection,
+ const gchar* property,
+ GVariant* value)> PropertySetter;
- explicit DBusServer();
+ DBusServer();
virtual ~DBusServer();
void Start(const std::string& name);
void SetIntrospectionXML(const std::string& xml);
GDBusNodeInfo* GetIntrospectionNodeInfo() const { return node_info_; }
+ void SendSignal(GDBusConnection* connection,
+ const std::string& iface, const std::string& signal_name,
+ GVariant* parameters);
+
void SetPeerCredentialsCallback(PeerCredentialsCallback func);
void SetMethodCallback(const std::string& iface, MethodCallback func);
void SetPropertyGetter(const std::string& iface, PropertyGetter func);
MethodCallback GetMethodCallback(const std::string& iface);
PropertySetter GetPropertySetter(const std::string& iface);
PropertyGetter GetPropertyGetter(const std::string& iface);
+
private:
GDBusServer* server_;
GDBusNodeInfo* node_info_;
--- /dev/null
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "common/profiler.h"
+
+#include "common/logger.h"
+#include "common/string_utils.h"
+
+namespace wrt {
+
+void PrintProfileLog(const char* func, const char* tag) {
+ LoggerD("[PROF] [%s] %s:%s", utils::GetCurrentMilliSeconds().c_str(),
+ func, tag);
+}
+
+} // namespace wrt
--- /dev/null
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WRT_COMMON_PROFILER_H_
+#define WRT_COMMON_PROFILER_H_
+
+namespace wrt {
+
+#define PROFILE_START() PrintProfileLog(__FUNCTION__, "START");
+#define PROFILE_END() PrintProfileLog(__FUNCTION__, "END");
+#define PROFILE(x) PrintProfileLog(__FUNCTION__, x);
+
+void PrintProfileLog(const char* func, const char* tag);
+
+} // namespace wrt
+
+#endif // WRT_COMMON_PROFILER_H_
#include "common/string_utils.h"
+#include <time.h>
+#include <math.h>
#include <uuid/uuid.h>
#include <string>
+#include <sstream>
+#include <iomanip>
#include <algorithm>
namespace wrt {
return str;
}
+std::string GetCurrentMilliSeconds() {
+ std::ostringstream ss;
+ struct timespec spec;
+ clock_gettime(CLOCK_REALTIME, &spec);
+ ss << spec.tv_sec << "." <<
+ std::setw(3) << std::setfill('0') << (round(spec.tv_nsec / 1.0e6));
+ return ss.str();
+}
+
} // namespace utils
} // namespace wrt
bool EndsWith(const std::string& str, const std::string& sub);
std::string ReplaceAll(const std::string& replace,
const std::string& from, const std::string& to);
+std::string GetCurrentMilliSeconds();
} // namespace utils
} // namespace wrt
# Dependencies
PKG_CHECK_MODULES(TARGET_EXTENSION_DEPS
+ uuid
dlog
glib-2.0
gio-2.0
#include "common/logger.h"
#include "common/constants.h"
#include "common/file_utils.h"
+#include "common/string_utils.h"
#include "extension/extension.h"
namespace wrt {
" </method>"
" <method name='CreateInstance'>"
" <arg name='extension_name' type='s' direction='in' />"
- " <arg name='instance_id' type='s' direction='in' />"
+ " <arg name='instance_id' type='s' direction='out' />"
" </method>"
" <method name='DestroyInstance'>"
" <arg name='instance_id' type='s' direction='in' />"
+ " <arg name='instance_id' type='s' direction='out' />"
" </method>"
- " <method name='CallASync'>"
+ " <method name='PostMessage'>"
" <arg name='instance_id' type='s' direction='in' />"
- " <arg name='body' type='s' direction='in' />"
+ " <arg name='msg' type='s' direction='in' />"
" </method>"
- " <method name='CallSync'>"
+ " <method name='SendSyncMessage'>"
" <arg name='instance_id' type='s' direction='in' />"
- " <arg name='body' type='s' direction='in' />"
+ " <arg name='msg' type='s' direction='in' />"
" <arg name='reply' type='s' direction='out' />"
" </method>"
" <signal name='OnMessageToJS'>"
" <arg name='instance_id' type='s' />"
- " <arg name='body' type='s' />"
+ " <arg name='msg' type='s' />"
" </signal>"
" </interface>"
"</node>";
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
+ using std::placeholders::_4;
dbus_server_.SetIntrospectionXML(kDBusIntrospectionXML);
dbus_server_.SetMethodCallback(
kDBusInterfaceNameForExtension,
- std::bind(&ExtensionServer::HandleDBusMethod, this, _1, _2, _3));
+ std::bind(&ExtensionServer::HandleDBusMethod, this, _1, _2, _3, _4));
dbus_server_.Start(app_uuid_ + "." + std::string(kDBusNameForExtension));
// Send 'ready' signal to Injected Bundle.
Extension* ext = new Extension(path, this);
if (!ext->Initialize() || !RegisterSymbols(ext)) {
delete ext;
+ return;
}
extensions_[ext->name()] = ext;
}
return true;
}
-void ExtensionServer::AddRuntimeVariable(const std::string& key,
- const std::string& value) {
- runtime_variables_.insert(std::make_pair(key, value));
-}
-
-void ExtensionServer::ClearRuntimeVariables() {
- runtime_variables_.clear();
-}
-
void ExtensionServer::GetRuntimeVariable(const char* key, char* value,
size_t value_len) {
- auto it = runtime_variables_.find(key);
- if (it != runtime_variables_.end()) {
- strncpy(value, it->second.c_str(), value_len);
- }
+ // TODO(wy80.choi): DBus Call to Runtime to get runtime variable
}
void ExtensionServer::NotifyEPCreatedToRuntime() {
NULL);
}
-void ExtensionServer::HandleDBusMethod(const std::string& method_name,
+void ExtensionServer::HandleDBusMethod(GDBusConnection* connection,
+ const std::string& method_name,
GVariant* parameters,
GDBusMethodInvocation* invocation) {
- // TODO(wy80.choi): Handle DBus Method Calls from InjectedBundle
+ LoggerD("HandleDBusMethod (%s)", method_name.c_str());
+
+ if (method_name == kMethodGetExtensions) {
+ OnGetExtensions(invocation);
+ } else if (method_name == kMethodCreateInstance) {
+ gchar* extension_name;
+ g_variant_get(parameters, "(&s)", &extension_name);
+ OnCreateInstance(connection, extension_name, invocation);
+ } else if (method_name == kMethodDestroyInstance) {
+ gchar* instance_id;
+ g_variant_get(parameters, "(&s)", &instance_id);
+ OnDestroyInstance(instance_id, invocation);
+ } else if (method_name == kMethodSendSyncMessage) {
+ gchar* instance_id;
+ gchar* msg;
+ g_variant_get(parameters, "(&s&s)", &instance_id, &msg);
+ OnSendSyncMessage(instance_id, msg, invocation);
+ } else if (method_name == kMethodPostMessage) {
+ gchar* instance_id;
+ gchar* msg;
+ g_variant_get(parameters, "(&s&s)", &instance_id, &msg);
+ OnPostMessage(instance_id, msg);
+ }
+}
+
+void ExtensionServer::OnGetExtensions(GDBusMethodInvocation* invocation) {
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+
+ // build an array of extensions
+ auto it = extensions_.begin();
+ for ( ; it != extensions_.end(); ++it) {
+ Extension* ext = it->second;
+ // open container for extension
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("(ssas)"));
+ g_variant_builder_add(&builder, "s", ext->name().c_str());
+ g_variant_builder_add(&builder, "s", ext->javascript_api().c_str());
+ // open container for entry_point
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("as"));
+ auto it_entry = ext->entry_points().begin();
+ for ( ; it_entry != ext->entry_points().end(); ++it_entry) {
+ g_variant_builder_add(&builder, "s", (*it_entry).c_str());
+ }
+ // close container('as') for entry_point
+ g_variant_builder_close(&builder);
+ // close container('(ssas)') for extension
+ g_variant_builder_close(&builder);
+ }
+ GVariant* reply = g_variant_builder_end(&builder);
+ g_dbus_method_invocation_return_value(
+ invocation, g_variant_new_tuple(&reply, 1));
+}
+
+void ExtensionServer::OnCreateInstance(
+ GDBusConnection* connection, const std::string& extension_name,
+ GDBusMethodInvocation* invocation) {
+ std::string instance_id = utils::GenerateUUID();
+
+ // find extension with given the extension name
+ auto it = extensions_.find(extension_name);
+ if (it == extensions_.end()) {
+ LoggerE("Failed to find extension [%s]", extension_name.c_str());
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Not found extension %s", extension_name.c_str());
+ return;
+ }
+
+ // create instance
+ ExtensionInstance* instance = it->second->CreateInstance();
+ if (!instance) {
+ LoggerE("Failed to create instance of extension [%s]",
+ extension_name.c_str());
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Failed to create instance of extension %s", extension_name.c_str());
+ return;
+ }
+
+ // set callbacks
+ using std::placeholders::_1;
+ instance->SetSendSyncReplyCallback(
+ std::bind(&ExtensionServer::SyncReplyCallback, this, _1, invocation));
+ instance->SetPostMessageCallback(
+ std::bind(&ExtensionServer::PostMessageToJSCallback,
+ this, connection, instance_id, _1));
+
+ instances_[instance_id] = instance;
+ g_dbus_method_invocation_return_value(
+ invocation, g_variant_new("(s)", instance_id.c_str()));
+}
+
+void ExtensionServer::OnDestroyInstance(
+ const std::string& instance_id, GDBusMethodInvocation* invocation) {
+ // find instance with the given instance id
+ auto it = instances_.find(instance_id);
+ if (it == instances_.end()) {
+ LoggerE("Failed to find instance [%s]", instance_id.c_str());
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Not found instance %s", instance_id.c_str());
+ return;
+ }
+
+ // destroy the instance
+ ExtensionInstance* instance = it->second;
+ delete instance;
+
+ instances_.erase(it);
+
+ g_dbus_method_invocation_return_value(
+ invocation, g_variant_new("(s)", instance_id.c_str()));
+}
+
+void ExtensionServer::OnSendSyncMessage(
+ const std::string& instance_id, const std::string& msg,
+ GDBusMethodInvocation* invocation) {
+ // find instance with the given instance id
+ auto it = instances_.find(instance_id);
+ if (it == instances_.end()) {
+ LoggerE("Failed to find instance [%s]", instance_id.c_str());
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Not found instance %s", instance_id.c_str());
+ return;
+ }
+
+ ExtensionInstance* instance = it->second;
+ instance->HandleSyncMessage(msg);
+
+ // reponse will be sent by SyncReplyCallback()
}
+// async
+void ExtensionServer::OnPostMessage(
+ const std::string& instance_id, const std::string& msg) {
+ auto it = instances_.find(instance_id);
+ if (it == instances_.end()) {
+ LoggerE("Failed to find instance [%s]", instance_id.c_str());
+ return;
+ }
+
+ ExtensionInstance* instance = it->second;
+ instance->HandleMessage(msg);
+}
+
+void ExtensionServer::SyncReplyCallback(
+ const std::string& reply, GDBusMethodInvocation* invocation) {
+ g_dbus_method_invocation_return_value(
+ invocation, g_variant_new("(s)", reply.c_str()));
+}
+
+void ExtensionServer::PostMessageToJSCallback(
+ GDBusConnection* connection, const std::string& instance_id,
+ const std::string& msg) {
+ if (!connection || g_dbus_connection_is_closed(connection)) {
+ LoggerE("Client connection is closed already.");
+ return;
+ }
+
+ dbus_server_.SendSignal(connection,
+ kDBusInterfaceNameForExtension,
+ kSignalOnMessageToJS,
+ g_variant_new("(ss)",
+ instance_id.c_str(),
+ msg.c_str()));
+}
} // namespace wrt
void RegisterSystemExtensions();
bool RegisterSymbols(Extension* extension);
- void AddRuntimeVariable(const std::string& key, const std::string& value);
void GetRuntimeVariable(const char* key, char* value, size_t value_len);
- void ClearRuntimeVariables();
void NotifyEPCreatedToRuntime();
- void HandleDBusMethod(const std::string& method_name,
+
+ void HandleDBusMethod(GDBusConnection* connection,
+ const std::string& method_name,
GVariant* parameters,
GDBusMethodInvocation* invocation);
+ void OnGetExtensions(GDBusMethodInvocation* invocation);
+ void OnCreateInstance(GDBusConnection* connection,
+ const std::string& extension_name,
+ GDBusMethodInvocation* invocation);
+ void OnDestroyInstance(const std::string& instance_id,
+ GDBusMethodInvocation* invocation);
+ void OnSendSyncMessage(const std::string& instance_id,
+ const std::string& msg,
+ GDBusMethodInvocation* invocation);
+ void OnPostMessage(const std::string& instance_id,
+ const std::string& msg);
+
+ void SyncReplyCallback(const std::string& reply,
+ GDBusMethodInvocation* invocation);
+
+ void PostMessageToJSCallback(GDBusConnection* connection,
+ const std::string& instance_id,
+ const std::string& msg);
+
std::string app_uuid_;
DBusServer dbus_server_;
DBusClient dbus_runtime_client_;
typedef std::set<std::string> StringSet;
StringSet extension_symbols_;
- typedef std::map<std::string, std::string> StringMap;
- StringMap runtime_variables_;
-
typedef std::map<std::string, Extension*> ExtensionMap;
ExtensionMap extensions_;
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
+ using std::placeholders::_4;
dbus_server_.SetIntrospectionXML(kDBusIntrospectionXML);
dbus_server_.SetMethodCallback(kDBusInterfaceNameForRuntime,
- std::bind(&Runtime::HandleDBusMethod, this, _1, _2, _3));
+ std::bind(&Runtime::HandleDBusMethod, this, _1, _2, _3, _4));
dbus_server_.Start(application_->uuid() +
"." + std::string(kDBusNameForRuntime));
}
}
-void Runtime::HandleDBusMethod(const std::string& method_name,
+void Runtime::HandleDBusMethod(GDBusConnection* connection,
+ const std::string& method_name,
GVariant* parameters,
GDBusMethodInvocation* invocation) {
if (method_name == kMethodNotifyEPCreated) {
virtual void OnLowMemory();
private:
- void HandleDBusMethod(const std::string& method_name,
+ void HandleDBusMethod(GDBusConnection* connection,
+ const std::string& method_name,
GVariant* parameters,
GDBusMethodInvocation* invocation);