atom_browser_main_parts.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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 <utility>
  6. #include "atom/browser/api/atom_api_app.h"
  7. #include "atom/browser/api/trackable_object.h"
  8. #include "atom/browser/atom_browser_client.h"
  9. #include "atom/browser/atom_browser_context.h"
  10. #include "atom/browser/browser.h"
  11. #include "atom/browser/io_thread.h"
  12. #include "atom/browser/javascript_environment.h"
  13. #include "atom/browser/node_debugger.h"
  14. #include "atom/common/api/atom_bindings.h"
  15. #include "atom/common/asar/asar_util.h"
  16. #include "atom/common/node_bindings.h"
  17. #include "base/command_line.h"
  18. #include "base/threading/thread_task_runner_handle.h"
  19. #include "chrome/browser/browser_process_impl.h"
  20. #include "chrome/browser/icon_manager.h"
  21. #include "chrome/browser/net/chrome_net_log_helper.h"
  22. #include "components/net_log/chrome_net_log.h"
  23. #include "components/net_log/net_export_file_writer.h"
  24. #include "content/public/browser/child_process_security_policy.h"
  25. #include "content/public/common/result_codes.h"
  26. #include "content/public/common/service_manager_connection.h"
  27. #include "electron/buildflags/buildflags.h"
  28. #include "services/device/public/mojom/constants.mojom.h"
  29. #include "services/network/public/cpp/network_switches.h"
  30. #include "services/service_manager/public/cpp/connector.h"
  31. #include "ui/base/idle/idle.h"
  32. #include "ui/base/l10n/l10n_util.h"
  33. #if defined(USE_X11)
  34. #include "chrome/browser/ui/libgtkui/gtk_util.h"
  35. #include "ui/events/devices/x11/touch_factory_x11.h"
  36. #endif
  37. #if BUILDFLAG(ENABLE_PDF_VIEWER)
  38. #include "atom/browser/atom_web_ui_controller_factory.h"
  39. #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
  40. #if defined(OS_MACOSX)
  41. #include "atom/browser/ui/cocoa/views_delegate_mac.h"
  42. #else
  43. #include "brightray/browser/views/views_delegate.h"
  44. #endif
  45. // Must be included after all other headers.
  46. #include "atom/common/node_includes.h"
  47. namespace atom {
  48. namespace {
  49. template <typename T>
  50. void Erase(T* container, typename T::iterator iter) {
  51. container->erase(iter);
  52. }
  53. } // namespace
  54. // static
  55. AtomBrowserMainParts* AtomBrowserMainParts::self_ = nullptr;
  56. AtomBrowserMainParts::AtomBrowserMainParts(
  57. const content::MainFunctionParams& params)
  58. : fake_browser_process_(new BrowserProcessImpl),
  59. browser_(new Browser),
  60. node_bindings_(NodeBindings::Create(NodeBindings::BROWSER)),
  61. atom_bindings_(new AtomBindings(uv_default_loop())),
  62. main_function_params_(params) {
  63. DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
  64. self_ = this;
  65. // Register extension scheme as web safe scheme.
  66. content::ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
  67. "chrome-extension");
  68. }
  69. AtomBrowserMainParts::~AtomBrowserMainParts() {
  70. asar::ClearArchives();
  71. // Leak the JavascriptEnvironment on exit.
  72. // This is to work around the bug that V8 would be waiting for background
  73. // tasks to finish on exit, while somehow it waits forever in Electron, more
  74. // about this can be found at
  75. // https://github.com/electron/electron/issues/4767. On the other handle there
  76. // is actually no need to gracefully shutdown V8 on exit in the main process,
  77. // we already ensured all necessary resources get cleaned up, and it would
  78. // make quitting faster.
  79. ignore_result(js_env_.release());
  80. }
  81. // static
  82. AtomBrowserMainParts* AtomBrowserMainParts::Get() {
  83. DCHECK(self_);
  84. return self_;
  85. }
  86. bool AtomBrowserMainParts::SetExitCode(int code) {
  87. if (!exit_code_)
  88. return false;
  89. *exit_code_ = code;
  90. return true;
  91. }
  92. int AtomBrowserMainParts::GetExitCode() {
  93. return exit_code_ != nullptr ? *exit_code_ : 0;
  94. }
  95. void AtomBrowserMainParts::RegisterDestructionCallback(
  96. base::OnceClosure callback) {
  97. // The destructors should be called in reversed order, so dependencies between
  98. // JavaScript objects can be correctly resolved.
  99. // For example WebContentsView => WebContents => Session.
  100. destructors_.insert(destructors_.begin(), std::move(callback));
  101. }
  102. int AtomBrowserMainParts::PreEarlyInitialization() {
  103. const int result = brightray::BrowserMainParts::PreEarlyInitialization();
  104. if (result != service_manager::RESULT_CODE_NORMAL_EXIT)
  105. return result;
  106. #if defined(OS_POSIX)
  107. HandleSIGCHLD();
  108. #endif
  109. return service_manager::RESULT_CODE_NORMAL_EXIT;
  110. }
  111. void AtomBrowserMainParts::PostEarlyInitialization() {
  112. brightray::BrowserMainParts::PostEarlyInitialization();
  113. // A workaround was previously needed because there was no ThreadTaskRunner
  114. // set. If this check is failing we may need to re-add that workaround
  115. DCHECK(base::ThreadTaskRunnerHandle::IsSet());
  116. // The ProxyResolverV8 has setup a complete V8 environment, in order to
  117. // avoid conflicts we only initialize our V8 environment after that.
  118. js_env_.reset(new JavascriptEnvironment(node_bindings_->uv_loop()));
  119. node_bindings_->Initialize();
  120. // Create the global environment.
  121. node::Environment* env = node_bindings_->CreateEnvironment(
  122. js_env_->context(), js_env_->platform());
  123. node_env_.reset(new NodeEnvironment(env));
  124. // Enable support for v8 inspector
  125. node_debugger_.reset(new NodeDebugger(env));
  126. node_debugger_->Start();
  127. // Add Electron extended APIs.
  128. atom_bindings_->BindTo(js_env_->isolate(), env->process_object());
  129. // Load everything.
  130. node_bindings_->LoadEnvironment(env);
  131. // Wrap the uv loop with global env.
  132. node_bindings_->set_uv_env(env);
  133. // We already initialized the feature list in
  134. // brightray::BrowserMainParts::PreEarlyInitialization(), but
  135. // the user JS script would not have had a chance to alter the command-line
  136. // switches at that point. Lets reinitialize it here to pick up the
  137. // command-line changes.
  138. base::FeatureList::ClearInstanceForTesting();
  139. brightray::BrowserMainParts::InitializeFeatureList();
  140. }
  141. int AtomBrowserMainParts::PreCreateThreads() {
  142. const int result = brightray::BrowserMainParts::PreCreateThreads();
  143. if (!result) {
  144. fake_browser_process_->SetApplicationLocale(
  145. brightray::BrowserClient::Get()->GetApplicationLocale());
  146. }
  147. #if defined(OS_MACOSX)
  148. ui::InitIdleMonitor();
  149. #endif
  150. net_log_ = std::make_unique<net_log::ChromeNetLog>();
  151. auto& command_line = main_function_params_.command_line;
  152. // start net log trace if --log-net-log is passed in the command line.
  153. if (command_line.HasSwitch(network::switches::kLogNetLog)) {
  154. base::FilePath log_file =
  155. command_line.GetSwitchValuePath(network::switches::kLogNetLog);
  156. if (!log_file.empty()) {
  157. net_log_->StartWritingToFile(
  158. log_file, GetNetCaptureModeFromCommandLine(command_line),
  159. command_line.GetCommandLineString(), std::string());
  160. }
  161. }
  162. // Initialize net log file exporter.
  163. net_log_->net_export_file_writer()->Initialize();
  164. // Manage global state of net and other IO thread related.
  165. io_thread_ = std::make_unique<IOThread>(net_log_.get());
  166. return result;
  167. }
  168. void AtomBrowserMainParts::PostDestroyThreads() {
  169. brightray::BrowserMainParts::PostDestroyThreads();
  170. io_thread_.reset();
  171. }
  172. void AtomBrowserMainParts::ToolkitInitialized() {
  173. brightray::BrowserMainParts::ToolkitInitialized();
  174. #if defined(OS_MACOSX)
  175. views_delegate_.reset(new ViewsDelegateMac);
  176. #else
  177. views_delegate_.reset(new brightray::ViewsDelegate);
  178. #endif
  179. }
  180. void AtomBrowserMainParts::PreMainMessageLoopRun() {
  181. // Run user's main script before most things get initialized, so we can have
  182. // a chance to setup everything.
  183. node_bindings_->PrepareMessageLoop();
  184. node_bindings_->RunMessageLoop();
  185. #if defined(USE_X11)
  186. ui::TouchFactory::SetTouchDeviceListFromCommandLine();
  187. #endif
  188. // Start idle gc.
  189. gc_timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(1),
  190. base::Bind(&v8::Isolate::LowMemoryNotification,
  191. base::Unretained(js_env_->isolate())));
  192. #if BUILDFLAG(ENABLE_PDF_VIEWER)
  193. content::WebUIControllerFactory::RegisterFactory(
  194. AtomWebUIControllerFactory::GetInstance());
  195. #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
  196. brightray::BrowserMainParts::PreMainMessageLoopRun();
  197. #if defined(USE_X11)
  198. libgtkui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
  199. #endif
  200. #if !defined(OS_MACOSX)
  201. // The corresponding call in macOS is in AtomApplicationDelegate.
  202. Browser::Get()->WillFinishLaunching();
  203. Browser::Get()->DidFinishLaunching(base::DictionaryValue());
  204. #endif
  205. // Notify observers that main thread message loop was initialized.
  206. Browser::Get()->PreMainMessageLoopRun();
  207. }
  208. bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
  209. js_env_->OnMessageLoopCreated();
  210. exit_code_ = result_code;
  211. return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
  212. }
  213. void AtomBrowserMainParts::PreDefaultMainMessageLoopRun(
  214. base::OnceClosure quit_closure) {
  215. Browser::SetMainMessageLoopQuitClosure(std::move(quit_closure));
  216. }
  217. void AtomBrowserMainParts::PostMainMessageLoopStart() {
  218. brightray::BrowserMainParts::PostMainMessageLoopStart();
  219. #if defined(OS_POSIX)
  220. HandleShutdownSignals();
  221. #endif
  222. }
  223. void AtomBrowserMainParts::PostMainMessageLoopRun() {
  224. brightray::BrowserMainParts::PostMainMessageLoopRun();
  225. js_env_->OnMessageLoopDestroying();
  226. #if defined(OS_MACOSX)
  227. FreeAppDelegate();
  228. #endif
  229. // Make sure destruction callbacks are called before message loop is
  230. // destroyed, otherwise some objects that need to be deleted on IO thread
  231. // won't be freed.
  232. // We don't use ranged for loop because iterators are getting invalided when
  233. // the callback runs.
  234. for (auto iter = destructors_.begin(); iter != destructors_.end();) {
  235. base::OnceClosure callback = std::move(*iter);
  236. if (!callback.is_null())
  237. std::move(callback).Run();
  238. ++iter;
  239. }
  240. }
  241. device::mojom::GeolocationControl*
  242. AtomBrowserMainParts::GetGeolocationControl() {
  243. if (geolocation_control_)
  244. return geolocation_control_.get();
  245. auto request = mojo::MakeRequest(&geolocation_control_);
  246. if (!content::ServiceManagerConnection::GetForProcess())
  247. return geolocation_control_.get();
  248. service_manager::Connector* connector =
  249. content::ServiceManagerConnection::GetForProcess()->GetConnector();
  250. connector->BindInterface(device::mojom::kServiceName, std::move(request));
  251. return geolocation_control_.get();
  252. }
  253. IconManager* AtomBrowserMainParts::GetIconManager() {
  254. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  255. if (!icon_manager_.get())
  256. icon_manager_.reset(new IconManager);
  257. return icon_manager_.get();
  258. }
  259. } // namespace atom