Initial Implementation of Node prelaunch 62/173962/9
authorws29.jung <ws29.jung@samsung.com>
Tue, 27 Mar 2018 07:41:37 +0000 (16:41 +0900)
committerjaekuk lee <juku1999@samsung.com>
Thu, 5 Apr 2018 23:44:52 +0000 (23:44 +0000)
This patch is created to reduce WebApp launching time by using
method of Node environment prelaunching.
Prelaunch will load and run electron.asar and app.asar
then it will wait until onCreate event emit.
onCreate event will be triggered when actual WebApp is launched.

Change-Id: I42f198e9755dd8e017691c22edf96eef15cb3eb5
Signed-off-by: ws29.jung <ws29.jung@samsung.com>
14 files changed:
atom/app/runtime.h
atom/app/ui_runtime.cc
atom/app/ui_runtime.h
atom/browser/api/atom_api_app.cc
atom/browser/api/atom_api_pwrt.cc
atom/browser/api/trackable_object.cc
atom/browser/atom_browser_main_parts.cc
atom/browser/atom_browser_main_parts.h
atom/browser/browser.cc
lib/browser/init.js
tizen/common/command_line.cc
tizen/common/command_line.h
tizen/src/wrt_main.cc
wrt/src/web_window.js

index baf9001..a5bcbc2 100644 (file)
@@ -31,9 +31,11 @@ class Runtime {
 
   virtual int Exec() = 0;
 
+  virtual void SetParam(content::ContentMainParams *params) = 0;
+
   static std::unique_ptr<Runtime> MakeRuntime(content::ContentMainParams *params);
 };
 
 }  // namespace runtime
 
-#endif  // RUNTIME_H_
\ No newline at end of file
+#endif  // RUNTIME_H_
index c773aca..7091bff 100644 (file)
@@ -22,6 +22,7 @@
 #include "atom/app/ui_runtime.h"
 #include "atom/browser/browser.h"
 #include "atom/browser/atom_browser_client.h"
+#include "atom/browser/atom_browser_main_parts.h"
 #include "atom/common/atom_command_line.h"
 #include "base/logging.h"
 #include "content/public/app/content_main.h"
 #include "tizen/common/app_control.h"
 #include "tizen/common/constants.h"
 
+#include "gin/v8_initializer.h"
+
 namespace runtime {
 
 UiRuntime::UiRuntime(content::ContentMainParams *params) {
   _params = params;
+
+  atom::AtomBrowserMainParts::SetNodeEnvironment();
 }
 
 UiRuntime::~UiRuntime() {
 }
 
+void UiRuntime::SetParam(content::ContentMainParams *params) {
+  if (_params)
+    LOG(ERROR) << "Use SetParam only when params is null";
+  else
+    _params = params;
+}
 
 bool UiRuntime::OnCreate() {
   return true;
index 1c8ec22..f32086b 100644 (file)
@@ -30,6 +30,7 @@ class UiRuntime : public Runtime {
   virtual ~UiRuntime();
 
   virtual int Exec();
+  virtual void SetParam(content::ContentMainParams *params);
 
  protected:
   virtual bool OnCreate();
index 115041d..638a769 100644 (file)
@@ -491,7 +491,8 @@ void OnIconDataAvailable(v8::Isolate* isolate,
 }  // namespace
 
 App::App(v8::Isolate* isolate) {
-  static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this);
+  if (AtomBrowserClient::Get())
+    static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this);
   Browser::Get()->AddObserver(this);
   content::GpuDataManager::GetInstance()->AddObserver(this);
   Init(isolate);
index e8a75a6..e89b1dd 100644 (file)
@@ -14,32 +14,35 @@ namespace atom {
 namespace api {
 
 PWRT::PWRT(v8::Isolate* isolate) {
-  LOG(INFO) << "PWRT::PWRT";
+  LOG(ERROR) << "PWRT::PWRT";
   Init(isolate);
 }
 
 PWRT::~PWRT() {
-  LOG(INFO) << "PWRT::~PWRT";
+  LOG(ERROR) << "PWRT::~PWRT";
 }
 
 std::string PWRT::GetMessage() {
-  LOG(INFO) << "PWRT::GetMessage";
+  LOG(ERROR) << "PWRT::GetMessage";
   return "message from C++";
 }
 
 std::string PWRT::GetPath() {
-  LOG(INFO) << "PWRT::GetPath";
+  LOG(ERROR) << "PWRT::GetPath";
   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);
-  // TODO: Use resource-manager's GetStartResource() for localized urls
-  std::string app_path = "file://" + app_data->application_path() + app_data->content_info()->src();
-  return app_path;
+  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
+    std::string app_path = "file://" + app_data->application_path() + app_data->content_info()->src();
+    return app_path;
+  }
+  return "";
 }
 
 bool PWRT::isTizenWebApp() {
-  LOG(INFO) << "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?
@@ -56,14 +59,14 @@ void PWRT::Log(const std::string& message) {
 
 // static
 mate::Handle<PWRT> PWRT::Create(v8::Isolate* isolate) {
-  LOG(INFO) << "PWRT::Create";
+  LOG(ERROR) << "PWRT::Create";
   return mate::CreateHandle(isolate, new PWRT(isolate));
 }
 
 // static
 void PWRT::BuildPrototype(
     v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> prototype) {
-  LOG(INFO) << "PWRT::BuildPrototype";
+  LOG(ERROR) << "PWRT::BuildPrototype";
   prototype->SetClassName(mate::StringToV8(isolate, "PWRT"));
   // TODO: Needs adding necessary interface methods
   mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
@@ -82,7 +85,7 @@ namespace {
 
 void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
                 v8::Local<v8::Context> context, void* priv) {
-  LOG(INFO) << "PWRT::Initialize";
+  LOG(ERROR) << "PWRT::Initialize";
   v8::Isolate* isolate = context->GetIsolate();
   mate::Dictionary dict(isolate, exports);
   // TODO: Expose this attribute only for Tizen web apps
index 502757a..59e43b2 100644 (file)
@@ -61,7 +61,8 @@ int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
 // static
 base::Closure TrackableObjectBase::RegisterDestructionCallback(
     const base::Closure& c) {
-  return atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(c);
+  if (atom::AtomBrowserMainParts::Get())
+    return atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(c);
 }
 
 }  // namespace mate
index c5155be..f718f86 100644 (file)
@@ -18,6 +18,7 @@
 #include "atom/common/node_bindings.h"
 #include "atom/common/node_includes.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "content/public/browser/child_process_security_policy.h"
@@ -25,6 +26,8 @@
 #include "device/geolocation/geolocation_provider.h"
 #include "v8/include/v8-debug.h"
 
+#include "gin/v8_initializer.h"
+
 #if defined(USE_X11)
 #include "chrome/browser/ui/libgtkui/gtk_util.h"
 #include "ui/events/devices/x11/touch_factory_x11.h"
@@ -61,16 +64,36 @@ void Erase(T* container, typename T::iterator iter) {
 }  // namespace
 
 // static
+bool g_prelaunch = false;
 AtomBrowserMainParts* AtomBrowserMainParts::self_ = nullptr;
+node::Environment* env_ = nullptr;
+scoped_refptr<BridgeTaskRunner> self_bridge_task_runner;
+std::unique_ptr<Browser> self_browser;
+std::unique_ptr<JavascriptEnvironment> self_js_env;
+std::unique_ptr<NodeBindings> self_node_bindings;
+std::unique_ptr<AtomBindings> self_atom_bindings;
+std::unique_ptr<NodeEnvironment> self_node_env;
+std::unique_ptr<NodeDebugger> self_node_debugger;
 
 AtomBrowserMainParts::AtomBrowserMainParts()
     : fake_browser_process_(new BrowserProcess),
       exit_code_(nullptr),
-      browser_(new Browser),
-      node_bindings_(NodeBindings::Create(NodeBindings::BROWSER)),
-      atom_bindings_(new AtomBindings(uv_default_loop())),
       gc_timer_(true, true) {
   DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
+  if (g_prelaunch) {
+    browser_ = std::move(self_browser);
+    node_bindings_ = std::move(self_node_bindings);
+    atom_bindings_ = std::move(self_atom_bindings);
+
+    js_env_ = std::move(self_js_env);
+    node_debugger_ = std::move(self_node_debugger);
+    bridge_task_runner_ = self_bridge_task_runner;
+    node_env_ = std::move(self_node_env);
+  } else {
+    browser_.reset(new Browser);
+    node_bindings_.reset(NodeBindings::Create(NodeBindings::BROWSER));
+    atom_bindings_.reset(new AtomBindings(uv_default_loop()));
+  }
   self_ = this;
   // Register extension scheme as web safe scheme.
   content::ChildProcessSecurityPolicy::GetInstance()->
@@ -95,6 +118,44 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() {
   return self_;
 }
 
+Browser* AtomBrowserMainParts::GetStaticBrowser() {
+  return self_browser.get();
+}
+
+void AtomBrowserMainParts::SetNodeEnvironment() {
+  if (g_prelaunch)
+    return;
+
+  std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  feature_list->InitializeFromCommandLine("", "");
+  base::FeatureList::SetInstance(std::move(feature_list));
+
+  gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
+
+  self_browser.reset(new atom::Browser);
+  self_bridge_task_runner = new atom::BridgeTaskRunner;
+  base::ThreadTaskRunnerHandle handle(self_bridge_task_runner);
+
+  self_js_env.reset(new atom::JavascriptEnvironment);
+  self_node_bindings.reset(atom::NodeBindings::Create(atom::NodeBindings::BROWSER));
+  self_atom_bindings.reset(new atom::AtomBindings(uv_default_loop()));
+  self_node_bindings->Initialize();
+
+  self_node_debugger.reset(new atom::NodeDebugger(self_js_env->isolate()));
+  env_ = self_node_bindings->CreateEnvironment(self_js_env->context());
+  self_node_env.reset(new atom::NodeEnvironment(env_));
+
+  if (self_node_debugger->IsRunning())
+    env_->AssignToContext(v8::Debug::GetDebugContext(self_js_env->isolate()));
+
+  self_atom_bindings->BindTo(self_js_env->isolate(), env_->process_object());
+
+  self_node_bindings->LoadEnvironment(env_);
+  self_node_bindings->set_uv_env(env_);
+  g_prelaunch = true;
+}
+
 bool AtomBrowserMainParts::SetExitCode(int code) {
   if (!exit_code_)
     return false;
@@ -122,6 +183,8 @@ void AtomBrowserMainParts::PreEarlyInitialization() {
 
 void AtomBrowserMainParts::PostEarlyInitialization() {
   brightray::BrowserMainParts::PostEarlyInitialization();
+  if (g_prelaunch)
+      return;
 
   // Temporary set the bridge_task_runner_ as current thread's task runner,
   // so we can fool gin::PerIsolateData to use it as its task runner, instead
index 2ba7d34..ca505f7 100644 (file)
@@ -43,7 +43,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
   // Returns a closure that can be used to remove |callback| from the list.
   base::Closure RegisterDestructionCallback(const base::Closure& callback);
 
+  static void SetNodeEnvironment();
+
   Browser* browser() { return browser_.get(); }
+  static Browser* GetStaticBrowser();
 
  protected:
   // content::BrowserMainParts:
index 2a36143..dea0bf2 100644 (file)
@@ -35,7 +35,10 @@ Browser::~Browser() {
 
 // static
 Browser* Browser::Get() {
-  return AtomBrowserMainParts::Get()->browser();
+  if (AtomBrowserMainParts::Get())
+    return AtomBrowserMainParts::Get()->browser();
+  else
+    return AtomBrowserMainParts::GetStaticBrowser();
 }
 
 void Browser::Quit() {
index a220069..6c8ac89 100644 (file)
@@ -169,7 +169,9 @@ app.setPath('userCache', path.join(app.getPath('cache'), app.getName()))
 app.setAppPath(packagePath)
 
 // Load the chrome extension support.
-require('./chrome-extension')
+// FIXME: When prelaunch, initializing electron modules
+//        in chrome-extension cause segmentation fault.
+//require('./chrome-extension')
 
 // Load internal desktop-capturer module.
 // FIXME: This is guard for bringup.
index 6ee518a..ecf6d3c 100644 (file)
@@ -131,10 +131,12 @@ void CommandLine::Reset() {
 }
 
 // static
-void CommandLine::Init(int argc, char* argv[]) {
+bool CommandLine::Init(int argc, char* argv[]) {
   if (!current_process_commandline_) {
     current_process_commandline_ = new CommandLine(argc, argv);
+    return true;
   }
+  return false;
 }
 
 // static
index 6854808..1c7bae0 100644 (file)
@@ -30,7 +30,7 @@ class CommandLine {
   // Arguments which except for option strings
   typedef std::vector<std::string> Arguments;
 
-  static void Init(int argc, char* argv[]);
+  static bool Init(int argc, char* argv[]);
   static CommandLine* ForCurrentProcess();
   static void Reset();
 
index 799621c..0bf3635 100644 (file)
@@ -138,6 +138,9 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
 #elif defined(OS_LINUX)  // defined(OS_WIN)
 
 #if defined(OS_TIZEN)
+bool g_initialized_ = false;
+std::unique_ptr<runtime::Runtime> runtime_;
+
 // For debug purpose only.
 // TODO: To be removed later
 bool hasTizenPackageID(int argc, const char* const* argv) {
@@ -153,6 +156,8 @@ int real_main(int argc, char* argv[]) {
 #else
 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;
@@ -160,7 +165,15 @@ int main(int argc, char* argv[]) {
   }
 
 #if defined(USE_EFL)
-  common::CommandLine::Init(argc, argv);
+  if (!common::CommandLine::Init(argc, argv)) {
+    common::CommandLine::Reset();
+    common::CommandLine::Init(argc, argv);
+  }
+
+  if (!base::CommandLine::Init(argc, 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");
 
@@ -172,9 +185,10 @@ int main(int argc, char* argv[]) {
       return false;
     }
   }
-
-  if (efl::Initialize(argc, const_cast<const char**>(argv)))
-    return 1;
+  if (!g_initialized_) {
+    if (efl::Initialize(argc, const_cast<const char**>(argv)))
+      return 1;
+  }
 
   // Add params for EFL port
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -193,8 +207,12 @@ int main(int argc, char* argv[]) {
 #if defined(OS_TIZEN)
   if (hasTizenPackageID(argc,argv)) { // TODO: Check to be removed later
     elm_init(argc, argv);
-    std::unique_ptr<runtime::Runtime> runtime = runtime::Runtime::MakeRuntime(&params);
-    return runtime->Exec();
+    if (!g_initialized_) {
+      runtime_ = runtime::Runtime::MakeRuntime(&params);
+    } else {
+      runtime_->SetParam(&params);
+    }
+    return runtime_->Exec();
   }
 #endif
   return content::ContentMain(params);
@@ -203,16 +221,29 @@ int main(int argc, char* argv[]) {
 #if defined(OS_TIZEN)
 __attribute__((visibility("default")))
 int main(int argc, const char* argv[]) {
+  for (int i = 0; i < argc; ++i)
+    LOG(ERROR) << "argv[" << i << "] : " << argv[i];
   if (strcmp(argv[0], "/usr/bin/wrt-loader") == 0) {
-    LOG(INFO) << "run with wrt-loader";
-    auto preload = [argv](void) {
+    LOG(ERROR) << "run with wrt-loader";
+    auto preload = [argc, argv](void) {
+      g_initialized_ = true;
+      if (efl::Initialize(argc, const_cast<const char**>(argv)))
+        return 1;
+
+      atom::AtomMainDelegate delegate;
+      content::ContentMainParams params(&delegate);
+      params.argc = argc;
+      params.argv = const_cast<const char**>(argv);
+      atom::AtomCommandLine::Init(argc, argv);
+      runtime_ = runtime::Runtime::MakeRuntime(nullptr);
+      return 0;
     };
     auto did_launch = [](const std::string& app_path) {
     };
     auto prelaunch = runtime::PreLauncher::Prelaunch;
     return prelaunch(argc, const_cast<char**>(argv), preload, did_launch, real_main);
   } else {
-    LOG(INFO) << "run without wrt-loader";
+    LOG(ERROR) << "run without wrt-loader";
     return real_main(argc, const_cast<char**>(argv));
   }
 }
index 9c552be..5258234 100644 (file)
@@ -212,7 +212,12 @@ class WebWindow {
         });
     }
     setUrl(path) {
-        this.mainWindow.loadURL(path);
+        if (path && (path.trim() != '')) {
+            this.mainWindow.loadURL(path);
+        } else {
+            const {pwrt} = require('electron');
+            this.mainWindow.loadURL(pwrt.getPath());
+        }
     }
     show() {
         this.mainWindow.show();