Initial service app implementation 54/181354/1
authorSangYong Park <sy302.park@samsung.com>
Mon, 9 Apr 2018 10:57:11 +0000 (19:57 +0900)
committerSangYong Park <sy302.park@samsung.com>
Tue, 12 Jun 2018 10:11:05 +0000 (19:11 +0900)
. add wrt-service executable
. change PWRT mate type to EventEmitter
 (TrackableObject cannot be instantiated without chromium.)

Change-Id: I2464fc12da1dcb7b85e70fcda950dd894222653f
Signed-off-by: SangYong Park <sy302.park@samsung.com>
35 files changed:
atom/app/ui_runtime.cc
atom/browser/api/atom_api_pwrt.cc [deleted file]
atom/browser/api/atom_api_pwrt.h [deleted file]
atom/browser/browser.cc
atom/browser/browser.h
atom/common/node_bindings.cc
lib/browser/api/module-list.js
lib/browser/api/pwrt.js [deleted file]
lib/browser/init.js
packaging/dbus.service [new file with mode: 0644]
packaging/electron-efl.spec
packaging/systemd.service [new file with mode: 0644]
tizen/common.gypi
tizen/common/application_data.cc
tizen/common/application_data.h
tizen/common/logger.h
tizen/extensions/common/xwalk_extension_server.cc
tizen/extensions/extensions.gyp
tizen/loader/wrt_loader.cc
tizen/renderer/injected_bundle.cc
tizen/src/app/service_main.cc [new file with mode: 0644]
tizen/src/browser/api/wrt_api_core.cc [new file with mode: 0644]
tizen/src/browser/api/wrt_api_core.h [new file with mode: 0644]
tizen/src/browser/wrt_ipc.cc [new file with mode: 0644]
tizen/src/browser/wrt_ipc.h [new file with mode: 0644]
tizen/src/browser/wrt_service.cc [new file with mode: 0644]
tizen/src/browser/wrt_service.h [new file with mode: 0644]
tizen/src/wrt_main.cc
vendor/node/src/node.cc
wrt.gyp
wrt/browser/wrt.js [new file with mode: 0644]
wrt/service/main.js [new file with mode: 0644]
wrt/src/main.js
wrt/src/runtime.js
wrt/src/web_window.js

index 27f7e0e..9bde160 100644 (file)
@@ -55,12 +55,7 @@ void UiRuntime::SetParam(content::ContentMainParams *params) {
 }
 
 bool UiRuntime::OnCreate() {
-  common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
-  std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
-
-  auto appdata_manager = common::ApplicationDataManager::GetInstance();
-  common::ApplicationData* appdata = appdata_manager->GetApplicationData(appid);
-
+  auto appdata = common::ApplicationDataManager::GetCurrentAppData();
   if(appdata->splash_screen_info()){
     atom::Browser* browser_model = atom::Browser::Get();
     browser_model->SetSplashScreen();
@@ -71,7 +66,6 @@ bool UiRuntime::OnCreate() {
 
 void UiRuntime::OnTerminate() {
   LOG(ERROR) << "OnTerminate()";
-  atom::Browser *browser_model = atom::Browser::Get();
 }
 
 void UiRuntime::OnPause() {
diff --git a/atom/browser/api/atom_api_pwrt.cc b/atom/browser/api/atom_api_pwrt.cc
deleted file mode 100644 (file)
index d23679c..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-#include "atom/browser/api/atom_api_pwrt.h"
-
-#include "atom/browser/browser.h"
-#include "native_mate/dictionary.h"
-#include "base/logging.h"
-
-#include "atom/common/node_includes.h"
-#include "tizen/common/application_data.h"
-#include "tizen/common/command_line.h"
-#include <dlog.h>
-
-namespace atom {
-
-namespace api {
-
-PWRT::PWRT(v8::Isolate* isolate) {
-  LOG(ERROR) << "PWRT::PWRT";
-  Init(isolate);
-}
-
-PWRT::~PWRT() {
-  LOG(ERROR) << "PWRT::~PWRT";
-}
-
-std::string PWRT::GetMessage() {
-  LOG(ERROR) << "PWRT::GetMessage";
-  return "message from C++";
-}
-
-std::string PWRT::GetPath() {
-  LOG(ERROR) << "PWRT::GetPath";
-  common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
-  if (runtime_cmd) {
-    std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
-    auto appdata_manager = common::ApplicationDataManager::GetInstance();
-    common::ApplicationData* app_data = appdata_manager->GetApplicationData(appid);
-    // TODO: Use resource-manager's GetStartResource() for localized urls
-    // atom::Browser *browser_model = atom::Browser::Get();
-    // std::unique_ptr<common::ResourceManager::Resource> res = browser_model->resource_manager_->GetStartResource(appcontrol.get());
-    if (app_data) {
-      std::string app_path = "file://" + app_data->application_path();
-      if (app_data->content_info())
-        app_path += app_data->content_info()->src();
-      else
-        app_path += "index.html";
-      return app_path;
-    }
-  }
-  return "";
-}
-
-bool PWRT::isTizenWebApp() {
-  LOG(ERROR) << "PWRT::isTizenWebApp";
-  common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
-  std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
-  if (appid != "electron") { // TODO: Any better distinguishing feature?
-    return true;
-  } else {
-    return false;
-  }
-}
-
-bool PWRT::isElectronLaunch() {
-  return Browser::Get()->is_electron_launch();
-}
-
-void PWRT::HideSplashScreen(int reason) {
-  LOG(ERROR) << "PWRT::HideSplashScreen";
-  atom::Browser *browser_model = atom::Browser::Get();
-  browser_model->HideSplashScreen(reason);
-}
-
-void PWRT::Log(const std::string& message) {
-  std::string output = "[JS LOG] " + message;
-  dlog_print(DLOG_ERROR, "WRT", output.c_str());
-}
-
-// static
-mate::Handle<PWRT> PWRT::Create(v8::Isolate* isolate) {
-  LOG(ERROR) << "PWRT::Create";
-  return mate::CreateHandle(isolate, new PWRT(isolate));
-}
-
-// static
-void PWRT::BuildPrototype(
-    v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> prototype) {
-  LOG(ERROR) << "PWRT::BuildPrototype";
-  prototype->SetClassName(mate::StringToV8(isolate, "PWRT"));
-  // TODO: Needs adding necessary interface methods
-  mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
-    .SetMethod("getMessage", &PWRT::GetMessage)
-    .SetMethod("getPath", &PWRT::GetPath)
-    .SetMethod("isTizenWebApp", &PWRT::isTizenWebApp)
-    .SetMethod("isElectronLaunch", &PWRT::isElectronLaunch)
-    .SetMethod("hideSplashScreen", &PWRT::HideSplashScreen)
-    .SetMethod("log", &PWRT::Log);
-}
-
-}  // namespace api
-
-}  // namespace atom
-
-
-namespace {
-
-void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
-                v8::Local<v8::Context> context, void* priv) {
-  LOG(ERROR) << "PWRT::Initialize";
-  v8::Isolate* isolate = context->GetIsolate();
-  mate::Dictionary dict(isolate, exports);
-  // TODO: Expose this attribute only for Tizen web apps
-  dict.Set("pwrt", atom::api::PWRT::Create(isolate));
-}
-
-}  // namespace
-
-NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_pwrt, Initialize)
diff --git a/atom/browser/api/atom_api_pwrt.h b/atom/browser/api/atom_api_pwrt.h
deleted file mode 100644 (file)
index ab25f34..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef ATOM_BROWSER_API_ATOM_API_PWRT_H_
-#define ATOM_BROWSER_API_ATOM_API_PWRT_H_
-
-#include "atom/browser/api/trackable_object.h"
-#include "base/compiler_specific.h"
-#include "native_mate/handle.h"
-
-namespace atom {
-
-namespace api {
-
-class PWRT : public mate::TrackableObject<PWRT> {
- public:
-  static mate::Handle<PWRT> Create(v8::Isolate* isolate);
-
-  static void BuildPrototype(v8::Isolate* isolate,
-                             v8::Local<v8::FunctionTemplate> prototype);
-
-  std::string GetMessage();
-  std::string GetPath();
-  bool isTizenWebApp();
-  bool isElectronLaunch();
-  void HideSplashScreen(int reason);
-  void Log(const std::string& message);
-
- protected:
-  explicit PWRT(v8::Isolate* isolate);
-  ~PWRT() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PWRT);
-};
-
-}  // namespace api
-
-}  // namespace atom
-
-#endif  // ATOM_BROWSER_API_ATOM_API_PWRT_H_
index b26b0e6..1110602 100644 (file)
@@ -30,13 +30,13 @@ namespace atom {
 Browser::Browser()
     : is_quiting_(false),
 #if defined(OS_TIZEN)
+      locale_manager_(new common::LocaleManager()),
+      launched_(false),
       is_electron_launch_(false),
 #endif
       is_exiting_(false),
       is_ready_(false),
-      is_shutdown_(false),
-      launched_(false),
-      locale_manager_(new common::LocaleManager()) {
+      is_shutdown_(false) {
   WindowList::AddObserver(this);
 }
 
@@ -127,10 +127,7 @@ void Browser::Shutdown() {
 #if defined(OS_TIZEN)
 void Browser::SetElectronAppLaunch() {
   if (!is_electron_launch_) {
-    common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
-    std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
-    auto appdata_manager = common::ApplicationDataManager::GetInstance();
-    common::ApplicationData* app_data = appdata_manager->GetApplicationData(appid);
+    auto app_data = common::ApplicationDataManager::GetCurrentAppData();
     if (app_data->content_info() && !strcmp(app_data->content_info()->src().c_str(), "package.json")) {
       is_electron_launch_ = true;
     }
@@ -274,16 +271,8 @@ void Browser::Show() {
 }
 
 void Browser::Initialize() {
-  common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
-  std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
-   //TODO: update the appid from binary name to electron
-  if (appid != "electron") {
-    auto appdata_manager = common::ApplicationDataManager::GetInstance();
-    common::ApplicationData* appdata = appdata_manager->GetApplicationData(appid);
-
-    resource_manager_.reset(
-        new common::ResourceManager(appdata, locale_manager_.get()));
-  }
+  auto appdata = common::ApplicationDataManager::GetCurrentAppData();
+  resource_manager_.reset(new common::ResourceManager(appdata, locale_manager_.get()));
 }
 
 void Browser::AppControl(std::unique_ptr<common::AppControl> appcontrol) {
@@ -324,14 +313,10 @@ void Browser::Launch(std::unique_ptr<common::AppControl> appcontrol) {
   launched_ = true;
 //To do:Implementation of relaunching of app
 }
+
 #if defined(OS_TIZEN)
 void Browser::SetSplashScreen() {
-  common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
-  std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
-
-  auto appdata_manager = common::ApplicationDataManager::GetInstance();
-  common::ApplicationData* appdata = appdata_manager->GetApplicationData(appid);
-
+  auto appdata = common::ApplicationDataManager::GetCurrentAppData();
   Evas_Object* window_ = elm_win_util_standard_add("", "");
 
   splash_screen_.reset(
@@ -340,13 +325,8 @@ void Browser::SetSplashScreen() {
 }
 
 void Browser::HideSplashScreen(int reason) {
-  common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
-  std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
-
-  auto appdata_manager = common::ApplicationDataManager::GetInstance();
-  common::ApplicationData* appdata = appdata_manager->GetApplicationData(appid);
-
-  if(appdata->splash_screen_info() == NULL) {
+  auto appdata = common::ApplicationDataManager::GetCurrentAppData();
+  if (!appdata->splash_screen_info()) {
     return;
   }
 
index c089fff..0e759e6 100644 (file)
@@ -50,13 +50,6 @@ class Browser : public WindowListObserver {
 
   static Browser* Get();
 
-  std::unique_ptr<common::ResourceManager> resource_manager_;
-  std::unique_ptr<common::LocaleManager> locale_manager_;
-#if defined(OS_TIZEN)
-  std::unique_ptr<SplashScreen> splash_screen_;
-#endif  // defined(OS_TIZEN)
-
-
   void Initialize();
   // Try to close all windows and quit the application.
   void Quit();
@@ -254,8 +247,6 @@ class Browser : public WindowListObserver {
 
   bool is_quiting_;
 
-  bool launched_;
-
  private:
   // WindowListObserver implementations:
   void OnWindowCloseCancelled(NativeWindow* window) override;
@@ -268,6 +259,14 @@ class Browser : public WindowListObserver {
   // Observers of the browser.
   base::ObserverList<BrowserObserver> observers_;
 
+#if defined(OS_TIZEN)
+  std::unique_ptr<common::ResourceManager> resource_manager_;
+  std::unique_ptr<common::LocaleManager> locale_manager_;
+  std::unique_ptr<SplashScreen> splash_screen_;
+  bool launched_;
+  bool is_electron_launch_;
+#endif
+
   // Whether `app.exit()` has been called
   bool is_exiting_;
 
@@ -277,10 +276,6 @@ class Browser : public WindowListObserver {
   // The browser is being shutdown.
   bool is_shutdown_;
 
-#if defined(OS_TIZEN)
-  bool is_electron_launch_;
-#endif
-
   std::string version_override_;
   std::string name_override_;
 
index 2a9c057..e61b6eb 100644 (file)
@@ -47,7 +47,6 @@ REFERENCE_MODULE(atom_browser_net);
 REFERENCE_MODULE(atom_browser_power_monitor);
 REFERENCE_MODULE(atom_browser_power_save_blocker);
 REFERENCE_MODULE(atom_browser_protocol);
-REFERENCE_MODULE(atom_browser_pwrt);
 REFERENCE_MODULE(atom_browser_render_process_preferences);
 REFERENCE_MODULE(atom_browser_session);
 REFERENCE_MODULE(atom_browser_system_preferences);
@@ -84,8 +83,7 @@ std::unique_ptr<const char*[]> StringVectorToArgArray(
 
 base::FilePath GetResourcesPath(bool is_browser) {
 #if defined(OS_TIZEN)
-  // TODO: We should fix hardcoded path.
-  return base::FilePath("/opt/usr/home/owner/data/electron");
+  return base::FilePath(FILE_PATH_LITERAL(TIZEN_RESOURCE_PATH));
 #endif
   auto command_line = base::CommandLine::ForCurrentProcess();
   base::FilePath exec_path(command_line->GetProgram());
index fcc07b3..64b2829 100644 (file)
@@ -21,6 +21,5 @@ module.exports = [
   {name: 'Tray', file: 'tray'},
   {name: 'webContents', file: 'web-contents'},
   // The internal modules, invisible unless you know their names.
-  {name: 'NavigationController', file: 'navigation-controller', private: true},
-  {name: 'pwrt', file: 'pwrt', private: true}
+  {name: 'NavigationController', file: 'navigation-controller', private: true}
 ]
diff --git a/lib/browser/api/pwrt.js b/lib/browser/api/pwrt.js
deleted file mode 100644 (file)
index 0019884..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-const {pwrt} = process.atomBinding('pwrt');
-
-module.exports = pwrt
index 6c8ac89..cfcf26f 100644 (file)
@@ -42,21 +42,6 @@ if (process.platform === 'win32') {
   process.stdout.write = process.stderr.write = streamWrite
 }
 
-let {pwrt} = require('electron');
-console.log = console.error = console.warn = function(...args) {
-  pwrt.log(util.format(...args));
-};
-process.stdout.write = process.stderr.write = function (chunk, encoding, callback) {
-  if (Buffer.isBuffer(chunk)) {
-    chunk = chunk.toString(encoding)
-  }
-  pwrt.log(chunk)
-  if (callback) {
-    callback()
-  }
-  return true
-}
-
 // Don't quit on fatal error.
 process.on('uncaughtException', function (error) {
   // Do nothing if the user has a custom uncaught exception handler.
diff --git a/packaging/dbus.service b/packaging/dbus.service
new file mode 100644 (file)
index 0000000..5d1ba5e
--- /dev/null
@@ -0,0 +1,5 @@
+[D-BUS Service]
+Name=org.tizen.wrt
+User=owner
+Exec=/bin/false
+SystemdService=wrt.service
index 91e9ae0..fad12e0 100755 (executable)
@@ -70,12 +70,14 @@ cp %{SOURCE1001} .
 %define _pkgid org.tizen.%{name}
 %define _xmldir %TZ_SYS_RO_PACKAGES
 %define _out out.tizen/out/D
+%define _resourcedir /opt/usr/home/owner/data/wrt
 %define extension_path %{_libdir}/tizen-extensions-crosswalk
 
 DEFINE_ARGS="
     libchromiumcontent_component=1
     use_efl=1
     is_tizen=1
+    tizen_resource_path=%{_resourcedir}
     injected_bundle_path=%{_libdir}/libxwalk_injected_bundle.so
     extension_path=%{extension_path}
 "
@@ -124,16 +126,22 @@ install -m 0644 packaging/%{_pkgid}.png             %{buildroot}/%{_icondir}
 install -m 0755 %{_out}/lib/libnode.so              %{buildroot}/%{_libdir}
 install -m 0755 %{_out}/wrt-loader                  %{buildroot}/%{_bindir}
 install -m 0755 %{_out}/wrt                         %{buildroot}/%{_bindir}
+install -m 0755 %{_out}/wrt-service                 %{buildroot}/%{_bindir}
 
 ln -s %{_bindir}/wrt %{buildroot}%{_bindir}/wrt-client
-ln -s %{_bindir}/wrt %{buildroot}%{_bindir}/xwalk_runtime
 
 # install resource.
-mkdir -p %{buildroot}/opt/usr/home/owner/data/org.tizen.electron-efl
-install -m 0755 %{_out}/resources/electron.asar     %{buildroot}/opt/usr/home/owner/data/org.tizen.electron-efl
+mkdir -p %{buildroot}%{_resourcedir}
+install -m 0755 %{_out}/resources/electron.asar     %{buildroot}%{_resourcedir}
 
 ./node_modules/asar/bin/asar p wrt %{_out}/resources/app.asar
-install -m 0755 %{_out}/resources/app.asar          %{buildroot}/opt/usr/home/owner/data/org.tizen.electron-efl
+install -m 0755 %{_out}/resources/app.asar          %{buildroot}%{_resourcedir}
+
+mkdir -p %{buildroot}%{_unitdir_user}
+install -m 0644 packaging/systemd.service           %{buildroot}%{_unitdir_user}/wrt.service
+
+mkdir -p %{buildroot}%{_datadir}/dbus-1/services
+install -m 0644 packaging/dbus.service              %{buildroot}%{_datadir}/dbus-1/services/org.tizen.wrt.service
 
 # injected bundle and extensions
 mkdir -p %{buildroot}%{extension_path}
@@ -154,33 +162,28 @@ install -p -m 644 %{_out}/gen/splash_screen.json %{buildroot}%{extension_path}
 install -p -m 644 %{_out}/lib/libsplash_screen_plugin.so %{buildroot}%{_libdir}
 
 %post
-# Owner account can't write /opt/usr/home/owner/data/org.tizen.electron-efl
-# which is created in 'install'. So we should copy resources in 'post'.
-cp -rf /opt/usr/home/owner/data/org.tizen.electron-efl /opt/usr/home/owner/data/electron
-chown -R owner:users /opt/usr/home/owner/data/electron
-rm -rf /opt/usr/home/owner/data/org.tizen.electron-efl
-
 # FIXME: Until electron-efl is released to platform,
 #        following command is needed to set wrt-loader
 #        as cap_setgid,cap_sys_admin+ei.
 /usr/share/security-config/set_capability
 
 %postun
-rm -rf /opt/usr/home/owner/data/electron
 
 %clean
 rm -fr %{buildroot}
 
 %files
 %manifest packaging/electron-efl.manifest
-/opt/usr/home/owner/data/org.tizen.electron-efl/*
+%{_resourcedir}/*
 %{_icondir}/%{_pkgid}.png
 %{_libdir}/libnode.so
 %{_xmldir}/%{_pkgid}.xml
+%{_unitdir_user}/wrt.service
+%{_datadir}/dbus-1/services/org.tizen.wrt.service
 %attr(755,root,root) %{_bindir}/wrt
 %attr(755,root,root) %{_bindir}/wrt-client
+%attr(755,root,root) %{_bindir}/wrt-service
 %attr(755,root,root) %{_bindir}/wrt-loader
-%attr(755,root,root) %{_bindir}/xwalk_runtime
 %attr(644,root,root) %{_datadir}/aul/wrt.loader
 %attr(644,root,root) %{_libdir}/libwrt_common.so
 %attr(644,root,root) %{_libdir}/libxwalk_extension_shared.so
diff --git a/packaging/systemd.service b/packaging/systemd.service
new file mode 100644 (file)
index 0000000..774fa29
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=WRT daemon
+
+[Service]
+Type=dbus
+BusName=org.tizen.wrt
+ExecStart=/usr/bin/wrt-service
+
+[Install]
+WantedBy=default.target
index b0c2055..5ec020d 100644 (file)
@@ -7,6 +7,7 @@
     'clang%': 0,
     'use_efl%': 0,
     'is_tizen%': 0,
+    'tizen_resource_path%': '',
     'tizen_product_tv%': 0,
   },
   'conditions': [
           'USE_EFL',
         ],
       },
-      'variables': {
-        'js_sources': [
-          '<(DEPTH)/lib/browser/api/pwrt.js',
-        ],
-      },
     }],  # use_efl==1
     ['is_tizen==1', {
       'target_defaults': {
         'defines': [
           'OS_TIZEN',
+          'TIZEN_RESOURCE_PATH="<(tizen_resource_path)"',
         ],
       },
       'variables': {
index 48b4f3a..13ecf5c 100644 (file)
@@ -43,14 +43,10 @@ const char* kWearableClockCategory = "http://tizen.org/category/wearable_clock";
 
 }  // namespace
 
-ApplicationData::ApplicationData(const std::string& appid)
-    : app_id_(appid), loaded_(false) {
+ApplicationData::ApplicationData(const std::string& app_id) {
   SCOPE_PROFILE();
-  char* res_path = app_get_resource_path();
-  if (res_path != NULL) {
-    application_path_ = std::string(res_path) + kWgtPath + kPathSeparator;
-    free(res_path);
-  }
+  if (init())
+    app_id_ = app_id;
 }
 
 ApplicationData::~ApplicationData() {}
@@ -118,6 +114,19 @@ std::shared_ptr<const wgt::parse::CSPInfo> ApplicationData::csp_report_info()
   return csp_report_info_;
 }
 
+const wgt::parse::ServiceInfo* ApplicationData::service_info() const {
+  if (!service_list_)
+    return nullptr;
+  auto iter = service_list_->services.begin();
+  auto end = service_list_->services.end();
+  for (; iter != end; ++iter) {
+    if (app_id_ == iter->id()) {
+      return &*iter;
+    }
+  }
+  return nullptr;
+}
+
 const std::string ApplicationData::pkg_id() const {
   if (pkg_id_.empty()) {
     app_info_h app_info;
@@ -153,13 +162,12 @@ ApplicationData::AppType ApplicationData::GetAppType() {
   return UI;
 }
 
-bool ApplicationData::LoadManifestData() {
-  if (loaded_) {
-    return true;
+bool ApplicationData::init() {
+  std::unique_ptr<char> res_path(app_get_resource_path());
+  if (res_path) {
+    application_path_ = std::string(res_path.get()) + kWgtPath + kPathSeparator;
   }
 
-  SCOPE_PROFILE();
-
   std::string config_xml_path(application_path_ + kConfigXml);
   if (!utils::Exists(config_xml_path)) {
     LOGGER(ERROR) << "Failed to load manifest data : No such file '"
@@ -227,6 +235,9 @@ bool ApplicationData::LoadManifestData() {
       widget_config_parser->GetManifestData(
           wgt::parse::CSPInfo::Report_only_key()));
 
+  service_list_ = std::static_pointer_cast<const wgt::parse::ServiceList>(
+      widget_config_parser->GetManifestData(wgt::parse::ServiceInfo::Key()));
+
   // Set default empty object
   if (widget_info_.get() == NULL) {
     widget_info_.reset(new wgt::parse::WidgetInfo);
@@ -236,28 +247,35 @@ bool ApplicationData::LoadManifestData() {
   }
 
   app_type_ = GetAppType();
-  loaded_ = true;
 
   return true;
 }
 
 // static
-ApplicationDataManager* ApplicationDataManager::GetInstance() {
-  static ApplicationDataManager self;
-  return &self;
+ApplicationDataManager& ApplicationDataManager::GetInstance() {
+  static ApplicationDataManager manager;
+  return manager;
 }
 
-ApplicationDataManager::ApplicationDataManager() {}
-
-ApplicationDataManager::~ApplicationDataManager() {}
-
-ApplicationData* ApplicationDataManager::GetApplicationData(
-    const std::string& appid) {
-  auto it = cache_.find(appid);
-  if (it == cache_.end()) {
-    cache_[appid].reset(new ApplicationData(appid));
+// static
+ApplicationData* ApplicationDataManager::SetCurrentAppID(
+    const std::string& app_id) {
+  ApplicationDataManager& manager = GetInstance();
+  auto it = manager.cache_.find(app_id);
+  if (it == manager.cache_.end()) {
+    std::unique_ptr<ApplicationData> data(new ApplicationData(app_id));
+    if (!data->app_id().empty()) {
+      manager.cache_[app_id] = std::move(data);
+      manager.current_ =  manager.cache_[app_id].get();
+    }
   }
-  return cache_[appid].get();
+  return manager.cache_[app_id].get();
+}
+
+// static
+ApplicationData* ApplicationDataManager::GetCurrentAppData() {
+  ApplicationDataManager& manager = GetInstance();
+  return manager.current_;
 }
 
 }  // namespace common
index 8f43cae..0429eb0 100644 (file)
@@ -43,11 +43,9 @@ class ApplicationData {
  public:
   enum AppType { UI = 0, IME, WATCH };
 
-  explicit ApplicationData(const std::string& appid);
+  explicit ApplicationData(const std::string& app_id);
   ~ApplicationData();
 
-  bool LoadManifestData();
-
   std::shared_ptr<const wgt::parse::AppControlInfoList> app_control_info_list()
       const;
   std::shared_ptr<const wgt::parse::CategoryInfoList> category_info_list()
@@ -66,6 +64,7 @@ class ApplicationData {
   std::shared_ptr<const wgt::parse::WarpInfo> warp_info() const;
   std::shared_ptr<const wgt::parse::CSPInfo> csp_info() const;
   std::shared_ptr<const wgt::parse::CSPInfo> csp_report_info() const;
+  const wgt::parse::ServiceInfo* service_info() const;
 
   const std::string application_path() const { return application_path_; }
   const std::string pkg_id() const;
@@ -73,6 +72,9 @@ class ApplicationData {
   ApplicationData::AppType app_type() { return app_type_; }
 
  private:
+  bool init();
+  ApplicationData::AppType GetAppType();
+
   std::shared_ptr<const wgt::parse::AppControlInfoList> app_control_info_list_;
   std::shared_ptr<const wgt::parse::CategoryInfoList> category_info_list_;
   std::shared_ptr<const wgt::parse::MetaDataInfo> meta_data_info_;
@@ -88,26 +90,27 @@ class ApplicationData {
   std::shared_ptr<const wgt::parse::WarpInfo> warp_info_;
   std::shared_ptr<const wgt::parse::CSPInfo> csp_info_;
   std::shared_ptr<const wgt::parse::CSPInfo> csp_report_info_;
-  ApplicationData::AppType GetAppType();
+  std::shared_ptr<const wgt::parse::ServiceList> service_list_;
 
   std::string application_path_;
   mutable std::string pkg_id_;
   std::string app_id_;
   ApplicationData::AppType app_type_;
-  bool loaded_;
 };
 
 class ApplicationDataManager {
  public:
-  static ApplicationDataManager* GetInstance();
-
-  ApplicationData* GetApplicationData(const std::string& appid);
+  static ApplicationData* SetCurrentAppID(const std::string& app_id);
+  static ApplicationData* GetCurrentAppData();
 
  private:
-  ApplicationDataManager();
-  virtual ~ApplicationDataManager();
+  static ApplicationDataManager& GetInstance();
+
+  ApplicationDataManager() : current_(nullptr) {};
+  virtual ~ApplicationDataManager() {};
 
   std::map<std::string, std::unique_ptr<ApplicationData>> cache_;
+  ApplicationData* current_;
 };
 
 }  // namespace common
index bce7013..029db80 100644 (file)
@@ -21,7 +21,7 @@
 #include <sstream>
 
 #undef LOGGER_TAG
-#define LOGGER_TAG "ELECTRON"
+#define LOGGER_TAG "WRT"
 
 #define _LOGGER_LOG(prio, fmt, args...) \
   LOG_(LOG_ID_MAIN, prio, LOGGER_TAG, fmt, ##args)
index 06c45e0..4c3b9fd 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <string>
 
-#include "atom/common/api/api_messages.h"
 #include "common/logger.h"
 #include "common/profiler.h"
 #include "common/string_utils.h"
index d22c755..ed7b380 100644 (file)
@@ -43,6 +43,7 @@
         'packages': [
           'chromium-efl',
           'elementary',
+          'jsoncpp',
         ],
       },
       'include_dirs': [
@@ -62,7 +63,6 @@
 #        ],
         'variables': {
           'packages': [
-            'jsoncpp',
           ],
         },
       },
index 1e756e0..1d37333 100644 (file)
@@ -22,7 +22,7 @@ int main(int argc, char* argv[]) {
   dlog_print(DLOG_INFO, "CHROMIUM", "Begin wrt-loader");
   void* handle = dlopen("/usr/bin/wrt", RTLD_NOW);
   if (!handle) {
-    dlog_print(DLOG_ERROR, "CHROMIUM", "Failed to load electorn");
+    dlog_print(DLOG_ERROR, "CHROMIUM", "Failed to load wrt (%s)", dlerror());
     return false;
   }
 
index e3ee3c9..c7e5061 100644 (file)
@@ -52,11 +52,8 @@ class BundleGlobalData {
   void Initialize(const std::string& app_id) {
     PreInitialize();
 
-    auto appdata_manager = common::ApplicationDataManager::GetInstance();
-    common::ApplicationData* app_data =
-        appdata_manager->GetApplicationData(app_id);
+    auto app_data = common::ApplicationDataManager::SetCurrentAppID(app_id);
 
-    app_data->LoadManifestData();
     // PreInitialized locale_manager_.reset(new common::LocaleManager);
     locale_manager_->EnableAutoUpdate(true);
     if (app_data->widget_info() != NULL &&
@@ -100,9 +97,7 @@ extern "C" void DynamicSetWidgetInfo(const char* tizen_id) {
   runtime::BundleGlobalData::GetInstance()->Initialize(tizen_id);
   extensions::XWalkExtensionRendererController& controller =
     extensions::XWalkExtensionRendererController::GetInstance();
-  auto appdata_manager = common::ApplicationDataManager::GetInstance();
-  common::ApplicationData* app_data =
-    appdata_manager->GetApplicationData(tizen_id);
+  auto app_data = common::ApplicationDataManager::GetCurrentAppData();
   controller.LoadUserExtensions(app_data->application_path());
 }
 
diff --git a/tizen/src/app/service_main.cc b/tizen/src/app/service_main.cc
new file mode 100644 (file)
index 0000000..4c1d84a
--- /dev/null
@@ -0,0 +1,95 @@
+#include <fstream>
+
+#include "atom/app/node_main.h"
+#include "base/at_exit.h"
+#include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "tizen/common/application_data.h"
+#include "tizen/src/browser/wrt_ipc.h"
+#include "tizen/src/browser/wrt_service.h"
+#include "vendor/node/deps/uv/include/uv.h"
+
+#define REFERENCE_MODULE(name) \
+  extern "C" void _register_ ## name(void); \
+  void (*wrt_register_ ## name)(void) = _register_ ## name
+REFERENCE_MODULE(atom_common_asar);
+REFERENCE_MODULE(wrt);
+#undef REFERENCE_MODULE
+
+int ServiceDaemon() {
+  tizen::ServiceManager::Get();
+
+  uv_thread_t dbus_thread;
+  uv_thread_create(&dbus_thread, [](void* data) {
+    tizen::IPC ipc(true);
+    ipc.AddMessageHandler("StartService", [](const char*, const char* app_id, const tizen::IPC::Message& message) {
+      tizen::ServiceManager::Get()->Prepare(app_id, message.Sender());
+    });
+    ipc.Listen();
+  }, nullptr);
+
+  base::i18n::InitializeICU();
+  base::AtExitManager atexit_manager;
+
+  PathService::Override(base::DIR_EXE, base::FilePath("/usr/lib/chromium-efl/"));
+
+  std::string resource_path(TIZEN_RESOURCE_PATH);
+  resource_path += "/app.asar/service/main.js";
+
+  char* arguments[] = { "wrtd", const_cast<char*>(resource_path.c_str()) };
+  atom::NodeMain(sizeof(arguments) / sizeof(char*), arguments);
+
+  LOG(ERROR) << "WRT deamon is terminated";
+  return 0;
+}
+
+int ServiceClient(const std::string& app_id) {
+  tizen::IPC ipc;
+  if (!ipc.SendMessage("StartService", app_id.c_str())) {
+    return 1;
+  }
+
+  ipc.AddMessageHandler("ReadFile", [](const char*, const char* argument, const tizen::IPC::Message& message) {
+    std::string file(argument);
+    auto app_data = common::ApplicationDataManager::GetCurrentAppData();
+    base::FilePath path(app_data->application_path());
+    if (file.empty()) {
+      const wgt::parse::ServiceInfo* info = app_data->service_info();
+      if (info)
+        path = path.Append(info->content());
+    } else {
+      path = path.Append(file);
+    }
+
+    std::ifstream in(path.value(), std::ios::in);
+    std::string content;
+    if (in) {
+      in.seekg(0, std::ios::end);
+      content.resize(in.tellg());
+      in.seekg(0, std::ios::beg);
+      in.read(&content[0], content.size());
+      in.close();
+    }
+
+    message.Reply(content.c_str());
+  });
+  ipc.AddMessageHandler("Done", [](const char*, const char*, const tizen::IPC::Message&) {
+    //dbus_connection_close(connection); // TODO : App is relaunched by platfrom after exit.
+  });
+
+  ipc.Listen();
+  return 0;
+}
+
+int main(int argc, char* argv[]) {
+  std::string app_id(basename(argv[0]));
+  if (common::ApplicationDataManager::SetCurrentAppID(app_id)) {
+    return ServiceClient(app_id);
+  } else {
+    return ServiceDaemon();
+  }
+
+  return 0;
+}
diff --git a/tizen/src/browser/api/wrt_api_core.cc b/tizen/src/browser/api/wrt_api_core.cc
new file mode 100644 (file)
index 0000000..51f0f00
--- /dev/null
@@ -0,0 +1,122 @@
+#include "tizen/src/browser/api/wrt_api_core.h"
+
+#include <dlog.h>
+
+#include "atom/browser/browser.h"
+#include "atom/common/node_includes.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "native_mate/dictionary.h"
+#include "tizen/common/application_data.h"
+#include "tizen/common/command_line.h"
+#include "tizen/src/browser/wrt_service.h"
+
+namespace tizen {
+
+namespace api {
+
+WebRuntime* WebRuntime::instance_ = nullptr;
+
+WebRuntime::WebRuntime(v8::Isolate* isolate) {
+  Init(isolate);
+  instance_ = this;
+}
+
+WebRuntime::~WebRuntime() {
+  instance_ = nullptr;
+}
+
+std::string WebRuntime::GetMessage() const {
+  return "message from C++";
+}
+
+std::string WebRuntime::GetPath() const {
+  auto app_data = common::ApplicationDataManager::GetCurrentAppData();
+  if (!app_data) {
+    return std::string();
+  }
+  // TODO: Use resource-manager's GetStartResource() for localized urls
+  base::FilePath path(app_data->application_path());
+  if (app_data->content_info()) {
+    path = path.Append(app_data->content_info()->src());
+  } else {
+    path = path.Append("index.html");
+  }
+  std::string app_path = "file://" + path.value();
+  return app_path;
+}
+
+bool WebRuntime::isTizenWebApp() const {
+  common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
+  if (!runtime_cmd)
+    return false;
+  std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/electron");
+  if (appid != "electron") { // TODO: Any better distinguishing feature?
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool WebRuntime::isElectronLaunch() const {
+  return atom::Browser::Get()->is_electron_launch();
+}
+
+void WebRuntime::HideSplashScreen(int reason) {
+  atom::Browser* browser_model = atom::Browser::Get();
+  browser_model->HideSplashScreen(reason);
+}
+
+void WebRuntime::Log(const std::string& message) const {
+  std::string output = "[JS LOG] " + message;
+  dlog_print(DLOG_INFO, "WRT", output.c_str());
+}
+
+std::string WebRuntime::ReadService(const std::string& app_id) const {
+  tizen::Service* service = tizen::ServiceManager::Get()->GetService(app_id);
+  if (!service) {
+    isolate()->ThrowException(v8::Exception::Error(mate::StringToV8(
+        isolate(), "Fail to find service app.")));
+    return std::string();
+  }
+  return service->ReadFile(std::string());
+}
+
+// static
+mate::Handle<WebRuntime> WebRuntime::Create(v8::Isolate* isolate) {
+  return mate::CreateHandle(isolate, new WebRuntime(isolate));
+}
+
+// static
+void WebRuntime::BuildPrototype(
+    v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> prototype) {
+  prototype->SetClassName(mate::StringToV8(isolate, "WRT"));
+  // TODO: Needs adding necessary interface methods
+  mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
+    .SetMethod("getMessage", &WebRuntime::GetMessage)
+    .SetMethod("getPath", &WebRuntime::GetPath)
+    .SetMethod("isTizenWebApp", &WebRuntime::isTizenWebApp)
+    .SetMethod("isElectronLaunch", &WebRuntime::isElectronLaunch)
+    .SetMethod("hideSplashScreen", &WebRuntime::HideSplashScreen)
+    .SetMethod("log", &WebRuntime::Log)
+    .SetMethod("readService", &WebRuntime::ReadService);
+}
+
+}  // namespace api
+
+}  // namespace tizen
+
+
+namespace {
+
+void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
+                v8::Local<v8::Context> context, void* priv) {
+  v8::Isolate* isolate = context->GetIsolate();
+  mate::Dictionary dict(isolate, exports);
+  // TODO: Expose this attribute only for Tizen web apps
+  dict.Set("wrt", tizen::api::WebRuntime::Create(isolate));
+}
+
+}  // namespace
+
+NODE_MODULE_CONTEXT_AWARE_BUILTIN(wrt, Initialize)
diff --git a/tizen/src/browser/api/wrt_api_core.h b/tizen/src/browser/api/wrt_api_core.h
new file mode 100644 (file)
index 0000000..6c27987
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef BROWSER_API_WRT_API_CORE_H_
+#define BROWSER_API_WRT_API_CORE_H_
+
+#include "atom/browser/api/event_emitter.h"
+#include "native_mate/handle.h"
+
+namespace tizen {
+
+namespace api {
+
+class WebRuntime : public mate::EventEmitter<WebRuntime> {
+ public:
+  static mate::Handle<WebRuntime> Create(v8::Isolate* isolate);
+
+  static void BuildPrototype(v8::Isolate* isolate,
+                             v8::Local<v8::FunctionTemplate> prototype);
+
+  static WebRuntime* GetInstance() { return instance_; }
+
+ protected:
+  explicit WebRuntime(v8::Isolate* isolate);
+  ~WebRuntime() override;
+
+ private:
+  std::string GetMessage() const;
+  std::string GetPath() const;
+  bool isTizenWebApp() const;
+  bool isElectronLaunch() const;
+  void HideSplashScreen(int reason);
+  void Log(const std::string& message) const;
+  std::string ReadService(const std::string& app_id) const;
+
+  static WebRuntime* instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebRuntime);
+};
+
+}  // namespace api
+
+}  // namespace tizen
+
+#endif  // BROWSER_API_WRT_API_CORE_H_
diff --git a/tizen/src/browser/wrt_ipc.cc b/tizen/src/browser/wrt_ipc.cc
new file mode 100644 (file)
index 0000000..72af83a
--- /dev/null
@@ -0,0 +1,170 @@
+#include "tizen/src/browser/wrt_ipc.h"
+
+#include "base/logging.h"
+
+namespace tizen {
+
+#define WRT_DBUS_NAME "org.tizen.wrt"
+#define WRT_DBUS_PATH "/org/tizen/wrt"
+
+IPC::Message::Message(DBusConnection* connection, DBusMessage* message)
+  : connection_(connection), message_(message) {}
+
+const char* IPC::Message::Sender() const {
+  return dbus_message_get_sender(message_);
+}
+
+void IPC::Message::Reply(const char* argument) const {
+  DBusMessage* reply = dbus_message_new_method_return(message_);
+  dbus_message_append_args(reply, DBUS_TYPE_STRING, &argument, DBUS_TYPE_INVALID);
+  dbus_connection_send(connection_, reply, nullptr);
+  dbus_message_unref(reply);
+}
+
+IPC::IPC(bool is_daemon) {
+  DBusError error;
+  dbus_error_init(&error);
+
+  connection_ = dbus_bus_get_private(DBUS_BUS_SESSION, &error);
+  if (!connection_) {
+    LOG(ERROR) << "DBus connection error : " << error.message;
+    dbus_error_free(&error);
+  }
+
+  if (is_daemon) {
+    int result = dbus_bus_request_name(connection_, WRT_DBUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
+    if (dbus_error_is_set(&error)) {
+      LOG(ERROR) << "Fail to request name : " << error.message;
+      dbus_error_free(&error);
+      return;
+    }
+    if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+      LOG(ERROR) << "Fail to become owner";
+      return;
+    }
+  }
+}
+
+IPC::~IPC() {
+  dbus_connection_close(connection_);
+  dbus_connection_unref(connection_);
+}
+
+// static
+DBusHandlerResult IPC::OnMessage(DBusConnection* connection, DBusMessage* message, void* user_data) {
+  int type = dbus_message_get_type(message);
+  if (type != DBUS_MESSAGE_TYPE_METHOD_CALL) {
+     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  std::string interface = dbus_message_get_interface(message);
+  if (interface != WRT_DBUS_NAME) {
+     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  std::string member = dbus_message_get_member(message);
+  IPC* ipc = reinterpret_cast<IPC*>(user_data);
+  auto iterator = ipc->message_handlers_.find(member);
+  if (iterator != ipc->message_handlers_.end()) {
+    DBusError error;
+    dbus_error_init(&error);
+    char* argument = nullptr;
+    if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &argument, DBUS_TYPE_INVALID)) {
+      LOG(ERROR) << "dbus message reply is not valid";
+      dbus_error_free(&error);
+    }
+
+    auto handler = iterator->second;
+    handler(member.c_str(), argument, Message(ipc->connection_, message));
+  }
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+void IPC::AddMessageHandler(const char* type, MessageHandler handler) {
+  if (message_handlers_.empty()) {
+    if (!dbus_connection_add_filter(connection_, OnMessage, this, nullptr)) {
+      LOG(ERROR) << "Fail to add message handler";
+      return;
+    }
+  }
+  message_handlers_[type] = handler;
+}
+
+void IPC::Listen() {
+  while (dbus_connection_read_write_dispatch(connection_, -1)) {
+    ; // empty loop body
+  }
+}
+
+DBusMessage* IPC::InternalSendMessage(const char* receiver, const char* type, const char* argument, bool need_reply) {
+  DBusMessage* message = dbus_message_new_method_call(receiver, WRT_DBUS_PATH, WRT_DBUS_NAME, type);
+  if (!message) {
+    LOG(ERROR) << "Fail to create dbus message";
+    return nullptr;
+  }
+
+  if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &argument, DBUS_TYPE_INVALID)) { 
+    LOG(ERROR) << "Fail to append dbus message argument";
+    return nullptr;
+  }
+
+  DBusError error;
+  dbus_error_init(&error);
+  if (need_reply) {
+    DBusMessage* reply = dbus_connection_send_with_reply_and_block(connection_, message, -1, &error);
+    dbus_message_unref(message);
+    if (!reply) {
+      LOG(ERROR) << "Fail to receive dbus message reply";
+      dbus_error_free(&error);
+      return nullptr;
+    }
+    message = reply;
+  } else {
+    dbus_connection_send(connection_, message, nullptr);
+    dbus_connection_flush(connection_);
+  }
+  if (dbus_error_is_set(&error)) {
+    LOG(ERROR) << "Fail to send message : " << error.message;
+    dbus_error_free(&error);
+    return nullptr;
+  }
+
+  return message;
+}
+
+bool IPC::SendMessage(const char* type, const char* argument) {
+  return SendMessage(WRT_DBUS_NAME, type, argument);
+}
+
+bool IPC::SendMessage(const char* receiver, const char* type, const char* argument) {
+  DBusMessage* message = InternalSendMessage(receiver, type, argument, false);
+  if (!message) {
+    return false;
+  }
+  dbus_message_unref(message);
+  return true;
+}
+
+bool IPC::SendMessageAndWaitReply(const char* receiver, const char* type, const char* argument, std::string& reply_argument) {
+  DBusMessage* reply = InternalSendMessage(receiver, type, argument, true);
+  if (!reply) {
+    return false;
+  }
+
+  if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_ERROR) {
+    DBusError error;
+    dbus_error_init(&error);
+    char* buffer = nullptr;
+    if (!dbus_message_get_args(reply, &error, DBUS_TYPE_STRING, &buffer, DBUS_TYPE_INVALID)) {
+      LOG(ERROR) << "dbus message reply is not valid";
+      dbus_error_free(&error);
+      return false;
+    }
+    reply_argument = buffer;
+  }
+  dbus_message_unref(reply);
+  return true;
+}
+
+}  // namespace tizen
diff --git a/tizen/src/browser/wrt_ipc.h b/tizen/src/browser/wrt_ipc.h
new file mode 100644 (file)
index 0000000..51c5511
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef BROWSER_WRT_IPC_H_
+#define BROWSER_WRT_IPC_H_
+
+#include <dbus/dbus.h>
+#include <functional>
+#include <map>
+#include <string>
+
+namespace tizen {
+
+class IPC {
+ public:
+  IPC(bool is_daemon = false);
+  ~IPC();
+
+  class Message {
+   public:
+    Message(DBusConnection* connection, DBusMessage* message);
+
+    const char* Sender() const;
+    void Reply(const char* argument) const;
+
+   private:
+    DBusConnection* connection_;
+    DBusMessage* message_;
+  };
+
+  typedef std::function<void(const char* type, const char* argument, const Message& message)> MessageHandler;
+
+  void AddMessageHandler(const char* type, MessageHandler handler);
+  void Listen();
+
+  bool SendMessage(const char* type, const char* argument);
+  bool SendMessage(const char* receiver, const char* type, const char* argument);
+  bool SendMessageAndWaitReply(const char* receiver, const char* type, const char* argument, std::string& reply_argument);
+
+ private:
+  static DBusHandlerResult OnMessage(DBusConnection* connection, DBusMessage* message, void* user_data);
+
+  DBusMessage* InternalSendMessage(const char* receiver, const char* type, const char* argument, bool need_reply);
+
+  DBusConnection* connection_;
+  std::map<const std::string, MessageHandler> message_handlers_;
+};
+
+}  // namespace tizen
+
+#endif  // BROWSER_WRT_IPC_H_
diff --git a/tizen/src/browser/wrt_service.cc b/tizen/src/browser/wrt_service.cc
new file mode 100644 (file)
index 0000000..c3f6314
--- /dev/null
@@ -0,0 +1,75 @@
+#include "tizen/src/browser/wrt_service.h"
+
+#include "base/logging.h"
+#include "tizen/src/browser/api/wrt_api_core.h"
+
+namespace tizen {
+
+Service::Service(std::string source_name)
+    : source_name_(source_name) {}
+
+const std::string Service::ReadFile(const std::string file) {
+  std::string content;
+  ServiceManager::Get()->ipc_.SendMessageAndWaitReply(source_name_.c_str(), "ReadFile", file.c_str(), content);
+  return content;
+}
+
+ServiceManager::ServiceManager() {
+  uv_async_init(uv_default_loop(), &handle_, OnMainThread);
+  handle_.data = this;
+  uv_mutex_init(&mutex_);
+}
+
+ServiceManager::~ServiceManager() {
+  uv_close(reinterpret_cast<uv_handle_t*>(&handle_), nullptr);
+  uv_mutex_destroy(&mutex_);
+}
+
+// static
+ServiceManager* ServiceManager::Get() {
+  static ServiceManager* manager = nullptr;
+  if (!manager) {
+    manager = new ServiceManager;
+  }
+  return manager;
+}
+
+Service* ServiceManager::GetService(const std::string app_id) {
+  auto iter = services_.find(app_id);
+  if (iter == services_.end()) {
+    return nullptr;
+  }
+  return iter->second;
+}
+
+void ServiceManager::Prepare(const std::string app_id, const std::string source_name) {
+  Service* service = new Service(source_name);
+  uv_mutex_lock(&mutex_);
+  prepared_services_.push_back(app_id);
+  services_[app_id] = service;
+  uv_mutex_unlock(&mutex_);
+  uv_async_send(&handle_);
+}
+
+// static
+void ServiceManager::OnMainThread(uv_async_t* handle) {
+  ServiceManager* manager = reinterpret_cast<ServiceManager*>(handle->data);
+  std::vector<std::string> services;
+
+  auto wrt = tizen::api::WebRuntime::GetInstance();
+  if (!wrt) {
+    LOG(ERROR) << "JS WRT object is not created";
+    return;
+  }
+
+  uv_mutex_lock(&manager->mutex_);
+  services.swap(manager->prepared_services_);
+  uv_mutex_unlock(&manager->mutex_);
+
+  for (auto it = services.begin(); it != services.end(); it++) {
+    std::string app_id = *it;
+    wrt->Emit("start-service", app_id);
+  }
+}
+
+}  // namespace tizen
diff --git a/tizen/src/browser/wrt_service.h b/tizen/src/browser/wrt_service.h
new file mode 100644 (file)
index 0000000..bc41981
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BROWSER_WRT_SERVICE_H_
+#define BROWSER_WRT_SERVICE_H_
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "tizen/src/browser/wrt_ipc.h"
+#include "vendor/node/deps/uv/include/uv.h"
+
+namespace tizen {
+
+class Service {
+ public:
+  Service(std::string source_name);
+
+  const std::string ReadFile(const std::string file);
+
+ private:
+  const std::string source_name_;
+};
+
+class ServiceManager {
+ public:
+  static ServiceManager* Get();
+
+  Service* GetService(const std::string app_id);
+  void Prepare(const std::string app_id, const std::string source_name);
+
+ private:
+  ServiceManager();
+  ~ServiceManager();
+
+  static void OnMainThread(uv_async_t* handle);
+
+  friend class Service;
+
+  uv_async_t handle_;
+  uv_mutex_t mutex_;
+  std::vector<std::string> prepared_services_;
+  std::map<std::string, Service*> services_;
+  IPC ipc_;
+};
+
+}  // namespace tizen
+
+#endif  // BROWSER_WRT_SERVICE_H_
index 8c8052b..fc0320d 100644 (file)
@@ -5,37 +5,16 @@
 #include "wrt_main.h"
 
 #include <stdlib.h>
-
-#if defined(OS_WIN)
-#include <windows.h>  // windows.h must be included first
-
-#include <shellapi.h>
-#include <shellscalingapi.h>
-#include <tchar.h>
-
-#include "atom/app/atom_main_delegate.h"
-#include "atom/common/crash_reporter/win/crash_service_main.h"
-#include "base/environment.h"
-#include "base/process/launch.h"
-#include "base/win/windows_version.h"
-#include "content/public/app/sandbox_helper_win.h"
-#include "sandbox/win/src/sandbox_types.h"
-#elif defined(OS_LINUX)  // defined(OS_WIN)
 #include "atom/app/atom_main_delegate.h"  // NOLINT
 #include "content/public/app/content_main.h"
-#else  // defined(OS_LINUX)
-#include "atom/app/atom_library_main.h"
-#endif  // defined(OS_MACOSX)
-
-#if defined(USE_EFL)
-#include "efl/init.h"
-#endif
 
 #include "atom/app/node_main.h"
 #include "atom/common/atom_command_line.h"
 #include "base/at_exit.h"
 #include "base/i18n/icu_util.h"
 
+#include "efl/init.h"
+
 #if defined(OS_TIZEN)
 #include <Elementary.h>
 
 
 namespace {
 
-const char* kRunAsNode = "ELECTRON_RUN_AS_NODE";
-
 // Default command line flags for all profiles and platforms
 const char* kDefaultCommandLineFlags[] = {
   "allow-file-access-from-files",
   "enable-tizen-app-container",
 };
 
-bool IsEnvSet(const char* name) {
-#if defined(OS_WIN)
-  size_t required_size;
-  getenv_s(&required_size, nullptr, 0, name);
-  return required_size != 0;
-#else
-  char* indicator = getenv(name);
-  return indicator && indicator[0] != '\0';
-#endif
-}
-
 }  // namespace
 
-#if defined(OS_WIN)
-int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
-  int argc = 0;
-  wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
-
-  bool run_as_node = IsEnvSet(kRunAsNode);
-
-  // Make sure the output is printed to console.
-  if (run_as_node || !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE"))
-    base::RouteStdioToConsole(false);
-
-  // Convert argv to to UTF8
-  char** argv = new char*[argc];
-  for (int i = 0; i < argc; i++) {
-    // Compute the size of the required buffer
-    DWORD size = WideCharToMultiByte(CP_UTF8,
-                                     0,
-                                     wargv[i],
-                                     -1,
-                                     NULL,
-                                     0,
-                                     NULL,
-                                     NULL);
-    if (size == 0) {
-      // This should never happen.
-      fprintf(stderr, "Could not convert arguments to utf8.");
-      exit(1);
-    }
-    // Do the actual conversion
-    argv[i] = new char[size];
-    DWORD result = WideCharToMultiByte(CP_UTF8,
-                                       0,
-                                       wargv[i],
-                                       -1,
-                                       argv[i],
-                                       size,
-                                       NULL,
-                                       NULL);
-    if (result == 0) {
-      // This should never happen.
-      fprintf(stderr, "Could not convert arguments to utf8.");
-      exit(1);
-    }
-  }
-
-  if (run_as_node) {
-    // Now that argv conversion is done, we can finally start.
-    base::AtExitManager atexit_manager;
-    base::i18n::InitializeICU();
-    return atom::NodeMain(argc, argv);
-  } else if (IsEnvSet("ELECTRON_INTERNAL_CRASH_SERVICE")) {
-    return crash_service::Main(cmd);
-  }
-
-  sandbox::SandboxInterfaceInfo sandbox_info = {0};
-  content::InitializeSandboxInfo(&sandbox_info);
-  atom::AtomMainDelegate delegate;
-
-  content::ContentMainParams params(&delegate);
-  params.instance = instance;
-  params.sandbox_info = &sandbox_info;
-  atom::AtomCommandLine::Init(argc, argv);
-  atom::AtomCommandLine::InitW(argc, wargv);
-  return content::ContentMain(params);
-}
-
-#elif defined(OS_LINUX)  // defined(OS_WIN)
+#define REFERENCE_MODULE(name) \
+  extern "C" void _register_ ## name(void); \
+  void (*wrt_register_ ## name)(void) = _register_ ## name
+REFERENCE_MODULE(wrt);
+#undef REFERENCE_MODULE
 
 #if defined(OS_TIZEN)
 bool g_initialized_ = false;
@@ -159,13 +63,7 @@ int main(int argc, char* argv[]) {
 #endif
   for (int i = 0; i < argc; ++i)
     LOG(ERROR) << "argv[" << i << "] : " << argv[i];
-  if (IsEnvSet(kRunAsNode)) {
-    base::i18n::InitializeICU();
-    base::AtExitManager atexit_manager;
-    return atom::NodeMain(argc, const_cast<char**>(argv));
-  }
 
-#if defined(USE_EFL)
   if (!common::CommandLine::Init(argc, argv)) {
     common::CommandLine::Reset();
     common::CommandLine::Init(argc, argv);
@@ -175,16 +73,13 @@ int main(int argc, char* argv[]) {
     base::CommandLine::Reset();
     base::CommandLine::Init(argc, argv);
   }
+
   common::CommandLine* runtime_cmd = common::CommandLine::ForCurrentProcess();
   std::string appid = runtime_cmd->GetAppIdFromCommandLine("/usr/bin/wrt");
 
   // load manifest
   if (appid != "wrt") { // TODO: Any better way to distinguish?
-    auto appdata_manager = common::ApplicationDataManager::GetInstance();
-    common::ApplicationData* appdata = appdata_manager->GetApplicationData(appid);
-    if (!appdata->LoadManifestData()) {
-      return false;
-    }
+    common::ApplicationDataManager::SetCurrentAppID(appid);
   }
   if (!g_initialized_) {
     if (efl::Initialize(argc, const_cast<const char**>(argv)))
@@ -198,7 +93,6 @@ int main(int argc, char* argv[]) {
   for (auto arg : kDefaultCommandLineFlags)
     command_line->AppendSwitch(const_cast<char*>(arg));
   efl::AppendPortParams(*command_line);
-#endif
 
   atom::AtomMainDelegate delegate;
   content::ContentMainParams params(&delegate);
@@ -250,15 +144,3 @@ int main(int argc, const char* argv[]) {
   }
 }
 #endif
-
-#else  // defined(OS_LINUX)
-
-int main(int argc, const char* argv[]) {
-  if (IsEnvSet(kRunAsNode)) {
-    return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv));
-  }
-
-  return AtomMain(argc, argv);
-}
-
-#endif  // defined(OS_MACOSX)
index 66233d4..aca7991 100644 (file)
@@ -94,6 +94,10 @@ typedef int mode_t;
 extern char **environ;
 #endif
 
+#if defined(OS_TIZEN)
+#include <dlog/dlog.h>
+#endif
+
 namespace node {
 
 using v8::Array;
@@ -273,6 +277,9 @@ static void PrintErrorString(const char* format, ...) {
   // Don't include the null character in the output
   CHECK_GT(n, 0);
   WriteConsoleW(stderr_handle, wbuf.data(), n - 1, nullptr, nullptr);
+#elif defined(OS_TIZEN)
+  dlog_print(DLOG_ERROR, "WRT", "[Node.js ERROR]");
+  dlog_vprint(DLOG_ERROR, "WRT", format, ap);
 #else
   vfprintf(stderr, format, ap);
 #endif
diff --git a/wrt.gyp b/wrt.gyp
index eef72f2..32f0a97 100644 (file)
--- a/wrt.gyp
+++ b/wrt.gyp
@@ -11,9 +11,9 @@
         '<(DEPTH)/electron.gyp:js2asar',
         '<(DEPTH)/electron.gyp:app2asar',
         'wrt_lib',
+        'wrt-service',
         '<(DEPTH)/tizen/common/common.gyp:wrt_common',
         '<(DEPTH)/tizen/loader/loader.gyp:wrt-loader',
-        '<(DEPTH)/tizen/extensions/extensions.gyp:xwalk_extension_shared',
         '<(DEPTH)/tizen/extensions/extensions.gyp:widget_plugin',
         '<(DEPTH)/tizen/extensions/extensions.gyp:splash_screen_plugin',
         '<(DEPTH)/tizen/renderer/injected_bundle.gyp:xwalk_injected_bundle',
@@ -28,8 +28,6 @@
         'tizen/src/wrt_main.h',
         'tizen/loader/prelauncher.h',
         'tizen/loader/prelauncher.cc',
-        'atom/browser/splash_screen.h',
-        'atom/browser/splash_screen.cc',
       ],
       'include_dirs': [
         'tizen/src',
       'cflags_cc': [ '-fPIC' ],
     },  # target wrt
     {
+      'target_name': 'wrt-service',
+      'type': 'executable',
+      'dependencies': [
+        'wrt_lib',
+        '<(DEPTH)/efl/build/system.gyp:capi-appfw-application',
+        '<(DEPTH)/tizen/common/common.gyp:wrt_common',
+      ],
+      'sources': [
+        'tizen/src/app/service_main.cc',
+      ],
+      'include_dirs': [
+        'tizen/src',
+      ],
+      'includes': [
+        'tizen/build/common.gypi',
+      ],
+    },  # target wrt-service
+    {
       'target_name': 'wrt_lib',
       'type': 'static_library',
       'dependencies': [
+        '<(DEPTH)/tizen/extensions/extensions.gyp:xwalk_extension_shared',
         'electron.gyp:atom_js2c',
         'vendor/pdf_viewer/pdf_viewer.gyp:pdf_viewer',
         'vendor/brightray/brightray.gyp:brightray',
         'atom/app/ui_runtime.h',
         'atom/browser/api/atom_api_menu_efl.cc',
         'atom/browser/api/atom_api_menu_efl.h',
-        'atom/browser/api/atom_api_pwrt.cc',
-        'atom/browser/api/atom_api_pwrt.h',
         'atom/browser/api/atom_api_web_contents_efl.cc',
         'atom/browser/common_web_contents_delegate_efl.cc',
         'atom/browser/native_browser_view_efl.cc',
         'atom/browser/native_browser_view_efl.h',
         'atom/browser/native_window_efl.cc',
         'atom/browser/native_window_efl.h',
+        'atom/browser/splash_screen.h',
+        'atom/browser/splash_screen.cc',
         'atom/browser/ui/accelerator_util_efl.cc',
         'atom/browser/ui/drag_util_efl.cc',
         'atom/browser/ui/file_dialog_efl.cc',
         'chromium_src/chrome/browser/extensions/global_shortcut_listener_ozone.cc',
         'chromium_src/chrome/browser/extensions/global_shortcut_listener_ozone.h',
         'chromium_src/chrome/browser/icon_loader_efllinux.cc',
+        'tizen/src/browser/api/wrt_api_core.cc',
+        'tizen/src/browser/api/wrt_api_core.h',
+        'tizen/src/browser/wrt_ipc.cc',
+        'tizen/src/browser/wrt_ipc.h',
+        'tizen/src/browser/wrt_service.cc',
+        'tizen/src/browser/wrt_service.h',
       ],
       'sources/': [
         # chromium-efl supports only tizen webrtc using CAPI
diff --git a/wrt/browser/wrt.js b/wrt/browser/wrt.js
new file mode 100644 (file)
index 0000000..36b4035
--- /dev/null
@@ -0,0 +1,21 @@
+const {wrt} = process.binding('wrt');
+const {EventEmitter} = require('events')
+const util = require('util')
+
+Object.setPrototypeOf(Object.getPrototypeOf(wrt), EventEmitter.prototype)
+
+module.exports = wrt
+
+console.log = console.error = console.warn = function(...args) {
+  wrt.log(util.format(...args));
+};
+process.stdout.write = process.stderr.write = function (chunk, encoding, callback) {
+  if (Buffer.isBuffer(chunk)) {
+    chunk = chunk.toString(encoding)
+  }
+  wrt.log(chunk)
+  if (callback) {
+    callback()
+  }
+  return true
+}
diff --git a/wrt/service/main.js b/wrt/service/main.js
new file mode 100644 (file)
index 0000000..264669c
--- /dev/null
@@ -0,0 +1,15 @@
+'use strict';
+
+const wrt = require('../browser/wrt');
+const vm = require('vm');
+
+wrt.on('start-service', (event, appID) => {
+  console.log('start service app : ' + appID);
+  let sandbox = { console: console };
+  let options = { filename: appID };
+  vm.runInNewContext(wrt.readService(appID), sandbox, options);
+})
+
+process.on('exit', (code) => {
+  console.log('Exit with code : ' + code);
+})
index c1045a5..e1ee03f 100644 (file)
@@ -1,6 +1,5 @@
 'use strict';
 
-const {pwrt} = require('electron');
 const path_debug = require('debug')('MAIN');
 const runtime = require('./runtime');
 const yargs = require('yargs');
@@ -32,7 +31,7 @@ let parseCommandLine = function() {
     return {
         appID: args.a,
         devMode: args.d,
-        path: args.p ? args.p : pwrt.getPath(),
+        path: args.p,
         windowSize: args.s
     };
 };
index 2c1a1de..e9a6ead 100755 (executable)
@@ -1,11 +1,12 @@
 'use strict';
 const EXTENSIONS_PATH = process.env.WAS_EXTENSIONS_PATH;
 const ExtensionManager = require('./extension_manager');
-const {app, ipcMain, pwrt} = require('electron');
+const {app, ipcMain} = require('electron');
 const IPC_MESSAGE = require('./ipc_message');
 const WAS_EVENT = require('./was_event');
 const WebApplication = require('./web_application');
 const events = require('./events');
+const wrt = require('../browser/wrt');
 const runtime_debug = require('debug')('RUNTIME');
 const try_debug = require('debug')('TRY');
 
@@ -51,9 +52,9 @@ class Runtime {
         });
         app.on('will-finish-launching', function(event) {
             runtime_debug('will-finish-launching');
-            if (pwrt.isElectronLaunch()) {
+            if (wrt.isElectronLaunch()) {
                 console.log("Electron App launch");
-                let filePath = pwrt.getPath();
+                let filePath = wrt.getPath();
                 let pkgJson = require(filePath.substr(7, filePath.length - 12));
                 let mainJsPath = filePath.substr(7, filePath.length - 19) +
                                                 (pkgJson.main || 'index.js');
@@ -68,7 +69,7 @@ class Runtime {
             if (!options.noExtensions) {
                 this.extensionManager.build();
             }
-            if (pwrt.isElectronLaunch()) {
+            if (wrt.isElectronLaunch()) {
                 this.extensionManager.activateAll(app);
                 return;
             }
index 95476d8..fe6c3b9 100644 (file)
@@ -1,8 +1,9 @@
 'use strict';
-const {BrowserWindow, app, pwrt} = require('electron');
+const {BrowserWindow, app} = require('electron');
 const IPC_MESSAGE = require('./ipc_message');
 const WAS_EVENT = require('./was_event');
 const events = require('./events');
+const wrt = require('../browser/wrt');
 const target_debug = require('debug')('TARGET');
 const webwindow_debug = require('debug')('WEBWINDOW');
 
@@ -125,7 +126,7 @@ class WebWindow {
         });
         this.mainWindow.webContents.on('did-finish-load', function() {
             webwindow_debug('WebWindow : webContents did-finish-load');
-            pwrt.hideSplashScreen(1);
+            wrt.hideSplashScreen(1);
 
             if(!options.show){
                 webwindow_debug('WebWindow : browserWindow show options is ',options.show);
@@ -221,8 +222,7 @@ class WebWindow {
         if (path && (path.trim() != '')) {
             this.mainWindow.loadURL(path);
         } else {
-            const {pwrt} = require('electron');
-            this.mainWindow.loadURL(pwrt.getPath());
+            this.mainWindow.loadURL(wrt.getPath());
         }
     }
     show() {