atom_browser_main_parts.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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/atom_api_app.h"
  6. #include "atom/browser/api/trackable_object.h"
  7. #include "atom/browser/atom_access_token_store.h"
  8. #include "atom/browser/atom_browser_client.h"
  9. #include "atom/browser/atom_browser_context.h"
  10. #include "atom/browser/atom_web_ui_controller_factory.h"
  11. #include "atom/browser/bridge_task_runner.h"
  12. #include "atom/browser/browser.h"
  13. #include "atom/browser/javascript_environment.h"
  14. #include "atom/browser/node_debugger.h"
  15. #include "atom/common/api/atom_bindings.h"
  16. #include "atom/common/asar/asar_util.h"
  17. #include "atom/common/node_bindings.h"
  18. #include "atom/common/node_includes.h"
  19. #include "base/command_line.h"
  20. #include "base/threading/thread_task_runner_handle.h"
  21. #include "chrome/browser/browser_process.h"
  22. #include "content/public/browser/child_process_security_policy.h"
  23. #include "device/geolocation/geolocation_delegate.h"
  24. #include "device/geolocation/geolocation_provider.h"
  25. #include "ui/base/l10n/l10n_util.h"
  26. #include "v8/include/v8-debug.h"
  27. #if defined(USE_X11)
  28. #include "chrome/browser/ui/libgtkui/gtk_util.h"
  29. #include "ui/events/devices/x11/touch_factory_x11.h"
  30. #endif
  31. namespace atom {
  32. namespace {
  33. // A provider of Geolocation services to override AccessTokenStore.
  34. class AtomGeolocationDelegate : public device::GeolocationDelegate {
  35. public:
  36. AtomGeolocationDelegate() {
  37. device::GeolocationProvider::GetInstance()
  38. ->UserDidOptIntoLocationServices();
  39. }
  40. scoped_refptr<device::AccessTokenStore> CreateAccessTokenStore() final {
  41. return new AtomAccessTokenStore();
  42. }
  43. private:
  44. DISALLOW_COPY_AND_ASSIGN(AtomGeolocationDelegate);
  45. };
  46. template<typename T>
  47. void Erase(T* container, typename T::iterator iter) {
  48. container->erase(iter);
  49. }
  50. } // namespace
  51. // static
  52. AtomBrowserMainParts* AtomBrowserMainParts::self_ = nullptr;
  53. AtomBrowserMainParts::AtomBrowserMainParts()
  54. : fake_browser_process_(new BrowserProcess),
  55. exit_code_(nullptr),
  56. browser_(new Browser),
  57. node_bindings_(NodeBindings::Create(NodeBindings::BROWSER)),
  58. atom_bindings_(new AtomBindings(uv_default_loop())),
  59. gc_timer_(true, true) {
  60. DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
  61. self_ = this;
  62. // Register extension scheme as web safe scheme.
  63. content::ChildProcessSecurityPolicy::GetInstance()->
  64. RegisterWebSafeScheme("chrome-extension");
  65. }
  66. AtomBrowserMainParts::~AtomBrowserMainParts() {
  67. asar::ClearArchives();
  68. // Leak the JavascriptEnvironment on exit.
  69. // This is to work around the bug that V8 would be waiting for background
  70. // tasks to finish on exit, while somehow it waits forever in Electron, more
  71. // about this can be found at https://github.com/electron/electron/issues/4767.
  72. // On the other handle there is actually no need to gracefully shutdown V8
  73. // on exit in the main process, we already ensured all necessary resources get
  74. // cleaned up, and it would make quitting faster.
  75. ignore_result(js_env_.release());
  76. }
  77. // static
  78. AtomBrowserMainParts* AtomBrowserMainParts::Get() {
  79. DCHECK(self_);
  80. return self_;
  81. }
  82. bool AtomBrowserMainParts::SetExitCode(int code) {
  83. if (!exit_code_)
  84. return false;
  85. *exit_code_ = code;
  86. return true;
  87. }
  88. int AtomBrowserMainParts::GetExitCode() {
  89. return exit_code_ != nullptr ? *exit_code_ : 0;
  90. }
  91. base::Closure AtomBrowserMainParts::RegisterDestructionCallback(
  92. const base::Closure& callback) {
  93. auto iter = destructors_.insert(destructors_.end(), callback);
  94. return base::Bind(&Erase<std::list<base::Closure>>, &destructors_, iter);
  95. }
  96. void AtomBrowserMainParts::PreEarlyInitialization() {
  97. brightray::BrowserMainParts::PreEarlyInitialization();
  98. #if defined(OS_POSIX)
  99. HandleSIGCHLD();
  100. #endif
  101. }
  102. void AtomBrowserMainParts::PostEarlyInitialization() {
  103. brightray::BrowserMainParts::PostEarlyInitialization();
  104. // Temporary set the bridge_task_runner_ as current thread's task runner,
  105. // so we can fool gin::PerIsolateData to use it as its task runner, instead
  106. // of getting current message loop's task runner, which is null for now.
  107. bridge_task_runner_ = new BridgeTaskRunner;
  108. base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
  109. // The ProxyResolverV8 has setup a complete V8 environment, in order to
  110. // avoid conflicts we only initialize our V8 environment after that.
  111. js_env_.reset(new JavascriptEnvironment);
  112. node_bindings_->Initialize();
  113. // Create the global environment.
  114. node::Environment* env =
  115. node_bindings_->CreateEnvironment(js_env_->context());
  116. node_env_.reset(new NodeEnvironment(env));
  117. // Enable support for v8 inspector
  118. node_debugger_.reset(new NodeDebugger(env));
  119. node_debugger_->Start(js_env_->platform());
  120. // Add Electron extended APIs.
  121. atom_bindings_->BindTo(js_env_->isolate(), env->process_object());
  122. // Load everything.
  123. node_bindings_->LoadEnvironment(env);
  124. // Wrap the uv loop with global env.
  125. node_bindings_->set_uv_env(env);
  126. // We already initialized the feature list in
  127. // brightray::BrowserMainParts::PreEarlyInitialization(), but
  128. // the user JS script would not have had a chance to alter the command-line
  129. // switches at that point. Lets reinitialize it here to pick up the
  130. // command-line changes.
  131. base::FeatureList::ClearInstanceForTesting();
  132. brightray::BrowserMainParts::InitializeFeatureList();
  133. }
  134. int AtomBrowserMainParts::PreCreateThreads() {
  135. const int result = brightray::BrowserMainParts::PreCreateThreads();
  136. if (!result) {
  137. fake_browser_process_->SetApplicationLocale(
  138. brightray::BrowserClient::Get()->GetApplicationLocale());
  139. }
  140. return result;
  141. }
  142. void AtomBrowserMainParts::PreMainMessageLoopRun() {
  143. js_env_->OnMessageLoopCreated();
  144. // Run user's main script before most things get initialized, so we can have
  145. // a chance to setup everything.
  146. node_bindings_->PrepareMessageLoop();
  147. node_bindings_->RunMessageLoop();
  148. #if defined(USE_X11)
  149. ui::TouchFactory::SetTouchDeviceListFromCommandLine();
  150. #endif
  151. // Start idle gc.
  152. gc_timer_.Start(
  153. FROM_HERE, base::TimeDelta::FromMinutes(1),
  154. base::Bind(&v8::Isolate::LowMemoryNotification,
  155. base::Unretained(js_env_->isolate())));
  156. content::WebUIControllerFactory::RegisterFactory(
  157. AtomWebUIControllerFactory::GetInstance());
  158. brightray::BrowserMainParts::PreMainMessageLoopRun();
  159. bridge_task_runner_->MessageLoopIsReady();
  160. bridge_task_runner_ = nullptr;
  161. #if defined(USE_X11)
  162. libgtkui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
  163. #endif
  164. #if !defined(OS_MACOSX)
  165. // The corresponding call in macOS is in AtomApplicationDelegate.
  166. Browser::Get()->WillFinishLaunching();
  167. std::unique_ptr<base::DictionaryValue> empty_info(new base::DictionaryValue);
  168. Browser::Get()->DidFinishLaunching(*empty_info);
  169. #endif
  170. // Notify observers that main thread message loop was initialized.
  171. Browser::Get()->PreMainMessageLoopRun();
  172. }
  173. bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
  174. exit_code_ = result_code;
  175. return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
  176. }
  177. void AtomBrowserMainParts::PostMainMessageLoopStart() {
  178. brightray::BrowserMainParts::PostMainMessageLoopStart();
  179. #if defined(OS_POSIX)
  180. HandleShutdownSignals();
  181. #endif
  182. device::GeolocationProvider::SetGeolocationDelegate(
  183. new AtomGeolocationDelegate());
  184. }
  185. void AtomBrowserMainParts::PostMainMessageLoopRun() {
  186. brightray::BrowserMainParts::PostMainMessageLoopRun();
  187. js_env_->OnMessageLoopDestroying();
  188. #if defined(OS_MACOSX)
  189. FreeAppDelegate();
  190. #endif
  191. // Make sure destruction callbacks are called before message loop is
  192. // destroyed, otherwise some objects that need to be deleted on IO thread
  193. // won't be freed.
  194. // We don't use ranged for loop because iterators are getting invalided when
  195. // the callback runs.
  196. for (auto iter = destructors_.begin(); iter != destructors_.end();) {
  197. base::Closure& callback = *iter;
  198. ++iter;
  199. callback.Run();
  200. }
  201. }
  202. } // namespace atom