atom_browser_main_parts.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/atom_browser_main_parts.h"
  5. #include "atom/browser/api/trackable_object.h"
  6. #include "atom/browser/atom_browser_client.h"
  7. #include "atom/browser/atom_browser_context.h"
  8. #include "atom/browser/bridge_task_runner.h"
  9. #include "atom/browser/browser.h"
  10. #include "atom/browser/javascript_environment.h"
  11. #include "atom/browser/node_debugger.h"
  12. #include "atom/common/api/atom_bindings.h"
  13. #include "atom/common/node_bindings.h"
  14. #include "atom/common/node_includes.h"
  15. #include "base/command_line.h"
  16. #include "base/threading/thread_task_runner_handle.h"
  17. #include "chrome/browser/browser_process.h"
  18. #include "content/public/browser/child_process_security_policy.h"
  19. #include "v8/include/v8-debug.h"
  20. #if defined(USE_X11)
  21. #include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
  22. #include "ui/events/devices/x11/touch_factory_x11.h"
  23. #endif
  24. namespace atom {
  25. template<typename T>
  26. void Erase(T* container, typename T::iterator iter) {
  27. container->erase(iter);
  28. }
  29. // static
  30. AtomBrowserMainParts* AtomBrowserMainParts::self_ = nullptr;
  31. AtomBrowserMainParts::AtomBrowserMainParts()
  32. : fake_browser_process_(new BrowserProcess),
  33. exit_code_(nullptr),
  34. browser_(new Browser),
  35. node_bindings_(NodeBindings::Create(true)),
  36. atom_bindings_(new AtomBindings),
  37. gc_timer_(true, true) {
  38. DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
  39. self_ = this;
  40. // Register extension scheme as web safe scheme.
  41. content::ChildProcessSecurityPolicy::GetInstance()->
  42. RegisterWebSafeScheme("chrome-extension");
  43. }
  44. AtomBrowserMainParts::~AtomBrowserMainParts() {
  45. // Leak the JavascriptEnvironment on exit.
  46. // This is to work around the bug that V8 would be waiting for background
  47. // tasks to finish on exit, while somehow it waits forever in Electron, more
  48. // about this can be found at https://github.com/electron/electron/issues/4767.
  49. // On the other handle there is actually no need to gracefully shutdown V8
  50. // on exit in the main process, we already ensured all necessary resources get
  51. // cleaned up, and it would make quitting faster.
  52. ignore_result(js_env_.release());
  53. }
  54. // static
  55. AtomBrowserMainParts* AtomBrowserMainParts::Get() {
  56. DCHECK(self_);
  57. return self_;
  58. }
  59. bool AtomBrowserMainParts::SetExitCode(int code) {
  60. if (!exit_code_)
  61. return false;
  62. *exit_code_ = code;
  63. return true;
  64. }
  65. int AtomBrowserMainParts::GetExitCode() {
  66. return exit_code_ != nullptr ? *exit_code_ : 0;
  67. }
  68. base::Closure AtomBrowserMainParts::RegisterDestructionCallback(
  69. const base::Closure& callback) {
  70. auto iter = destructors_.insert(destructors_.end(), callback);
  71. return base::Bind(&Erase<std::list<base::Closure>>, &destructors_, iter);
  72. }
  73. void AtomBrowserMainParts::PreEarlyInitialization() {
  74. brightray::BrowserMainParts::PreEarlyInitialization();
  75. #if defined(OS_POSIX)
  76. HandleSIGCHLD();
  77. #endif
  78. }
  79. void AtomBrowserMainParts::PostEarlyInitialization() {
  80. brightray::BrowserMainParts::PostEarlyInitialization();
  81. // Temporary set the bridge_task_runner_ as current thread's task runner,
  82. // so we can fool gin::PerIsolateData to use it as its task runner, instead
  83. // of getting current message loop's task runner, which is null for now.
  84. bridge_task_runner_ = new BridgeTaskRunner;
  85. base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
  86. // The ProxyResolverV8 has setup a complete V8 environment, in order to
  87. // avoid conflicts we only initialize our V8 environment after that.
  88. js_env_.reset(new JavascriptEnvironment);
  89. node_bindings_->Initialize();
  90. // Support the "--debug" switch.
  91. node_debugger_.reset(new NodeDebugger(js_env_->isolate()));
  92. // Create the global environment.
  93. node::Environment* env =
  94. node_bindings_->CreateEnvironment(js_env_->context());
  95. // Make sure node can get correct environment when debugging.
  96. if (node_debugger_->IsRunning())
  97. env->AssignToContext(v8::Debug::GetDebugContext());
  98. // Add Electron extended APIs.
  99. atom_bindings_->BindTo(js_env_->isolate(), env->process_object());
  100. // Load everything.
  101. node_bindings_->LoadEnvironment(env);
  102. // Wrap the uv loop with global env.
  103. node_bindings_->set_uv_env(env);
  104. }
  105. void AtomBrowserMainParts::PreMainMessageLoopRun() {
  106. js_env_->OnMessageLoopCreated();
  107. // Run user's main script before most things get initialized, so we can have
  108. // a chance to setup everything.
  109. node_bindings_->PrepareMessageLoop();
  110. node_bindings_->RunMessageLoop();
  111. #if defined(USE_X11)
  112. ui::TouchFactory::SetTouchDeviceListFromCommandLine();
  113. #endif
  114. // Start idle gc.
  115. gc_timer_.Start(
  116. FROM_HERE, base::TimeDelta::FromMinutes(1),
  117. base::Bind(&v8::Isolate::LowMemoryNotification,
  118. base::Unretained(js_env_->isolate())));
  119. brightray::BrowserMainParts::PreMainMessageLoopRun();
  120. bridge_task_runner_->MessageLoopIsReady();
  121. bridge_task_runner_ = nullptr;
  122. #if defined(USE_X11)
  123. libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
  124. #endif
  125. #if !defined(OS_MACOSX)
  126. // The corresponding call in macOS is in AtomApplicationDelegate.
  127. Browser::Get()->WillFinishLaunching();
  128. std::unique_ptr<base::DictionaryValue> empty_info(new base::DictionaryValue);
  129. Browser::Get()->DidFinishLaunching(*empty_info);
  130. #endif
  131. }
  132. bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
  133. exit_code_ = result_code;
  134. return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
  135. }
  136. void AtomBrowserMainParts::PostMainMessageLoopStart() {
  137. brightray::BrowserMainParts::PostMainMessageLoopStart();
  138. #if defined(OS_POSIX)
  139. HandleShutdownSignals();
  140. #endif
  141. }
  142. void AtomBrowserMainParts::PostMainMessageLoopRun() {
  143. brightray::BrowserMainParts::PostMainMessageLoopRun();
  144. js_env_->OnMessageLoopDestroying();
  145. #if defined(OS_MACOSX)
  146. FreeAppDelegate();
  147. #endif
  148. // Make sure destruction callbacks are called before message loop is
  149. // destroyed, otherwise some objects that need to be deleted on IO thread
  150. // won't be freed.
  151. // We don't use ranged for loop because iterators are getting invalided when
  152. // the callback runs.
  153. for (auto iter = destructors_.begin(); iter != destructors_.end();) {
  154. base::Closure& callback = *iter;
  155. ++iter;
  156. callback.Run();
  157. }
  158. }
  159. } // namespace atom