electron_browser_main_parts.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  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 "shell/browser/electron_browser_main_parts.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/base_switches.h"
  10. #include "base/command_line.h"
  11. #include "base/feature_list.h"
  12. #include "base/i18n/rtl.h"
  13. #include "base/metrics/field_trial.h"
  14. #include "base/nix/xdg_util.h"
  15. #include "base/path_service.h"
  16. #include "base/run_loop.h"
  17. #include "base/strings/string_number_conversions.h"
  18. #include "base/strings/utf_string_conversions.h"
  19. #include "base/task/single_thread_task_runner.h"
  20. #include "chrome/browser/icon_manager.h"
  21. #include "chrome/browser/ui/color/chrome_color_mixers.h"
  22. #include "chrome/common/chrome_paths.h"
  23. #include "chrome/common/chrome_switches.h"
  24. #include "components/os_crypt/sync/key_storage_config_linux.h"
  25. #include "components/os_crypt/sync/key_storage_util_linux.h"
  26. #include "components/os_crypt/sync/os_crypt.h"
  27. #include "content/browser/browser_main_loop.h" // nogncheck
  28. #include "content/public/browser/browser_child_process_host_delegate.h"
  29. #include "content/public/browser/browser_child_process_host_iterator.h"
  30. #include "content/public/browser/browser_thread.h"
  31. #include "content/public/browser/child_process_data.h"
  32. #include "content/public/browser/child_process_security_policy.h"
  33. #include "content/public/browser/device_service.h"
  34. #include "content/public/browser/first_party_sets_handler.h"
  35. #include "content/public/browser/web_ui_controller_factory.h"
  36. #include "content/public/common/content_features.h"
  37. #include "content/public/common/content_switches.h"
  38. #include "content/public/common/process_type.h"
  39. #include "content/public/common/result_codes.h"
  40. #include "electron/buildflags/buildflags.h"
  41. #include "electron/fuses.h"
  42. #include "media/base/localized_strings.h"
  43. #include "services/network/public/cpp/features.h"
  44. #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
  45. #include "shell/app/electron_main_delegate.h"
  46. #include "shell/browser/api/electron_api_app.h"
  47. #include "shell/browser/api/electron_api_utility_process.h"
  48. #include "shell/browser/browser.h"
  49. #include "shell/browser/browser_process_impl.h"
  50. #include "shell/browser/electron_browser_client.h"
  51. #include "shell/browser/electron_browser_context.h"
  52. #include "shell/browser/electron_web_ui_controller_factory.h"
  53. #include "shell/browser/feature_list.h"
  54. #include "shell/browser/javascript_environment.h"
  55. #include "shell/browser/media/media_capture_devices_dispatcher.h"
  56. #include "shell/browser/ui/devtools_manager_delegate.h"
  57. #include "shell/common/api/electron_bindings.h"
  58. #include "shell/common/application_info.h"
  59. #include "shell/common/electron_paths.h"
  60. #include "shell/common/gin_helper/trackable_object.h"
  61. #include "shell/common/logging.h"
  62. #include "shell/common/node_bindings.h"
  63. #include "shell/common/node_includes.h"
  64. #include "third_party/abseil-cpp/absl/types/optional.h"
  65. #include "ui/base/idle/idle.h"
  66. #include "ui/base/l10n/l10n_util.h"
  67. #include "ui/base/ui_base_switches.h"
  68. #include "ui/color/color_provider_manager.h"
  69. #if defined(USE_AURA)
  70. #include "ui/display/display.h"
  71. #include "ui/display/screen.h"
  72. #include "ui/views/widget/desktop_aura/desktop_screen.h"
  73. #include "ui/wm/core/wm_state.h"
  74. #endif
  75. #if BUILDFLAG(IS_LINUX)
  76. #include "base/environment.h"
  77. #include "device/bluetooth/bluetooth_adapter_factory.h"
  78. #include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h"
  79. #include "electron/electron_gtk_stubs.h"
  80. #include "ui/base/cursor/cursor_factory.h"
  81. #include "ui/base/ime/linux/linux_input_method_context_factory.h"
  82. #include "ui/gfx/color_utils.h"
  83. #include "ui/gtk/gtk_compat.h" // nogncheck
  84. #include "ui/gtk/gtk_util.h" // nogncheck
  85. #include "ui/linux/linux_ui.h"
  86. #include "ui/linux/linux_ui_factory.h"
  87. #include "ui/linux/linux_ui_getter.h"
  88. #include "ui/ozone/public/ozone_platform.h"
  89. #endif
  90. #if BUILDFLAG(IS_WIN)
  91. #include "ui/base/l10n/l10n_util_win.h"
  92. #include "ui/gfx/system_fonts_win.h"
  93. #include "ui/strings/grit/app_locale_settings.h"
  94. #endif
  95. #if BUILDFLAG(IS_MAC)
  96. #include "components/os_crypt/sync/keychain_password_mac.h"
  97. #include "shell/browser/ui/cocoa/views_delegate_mac.h"
  98. #else
  99. #include "shell/browser/ui/views/electron_views_delegate.h"
  100. #endif
  101. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  102. #include "components/keyed_service/content/browser_context_dependency_manager.h"
  103. #include "extensions/browser/browser_context_keyed_service_factories.h"
  104. #include "extensions/common/extension_api.h"
  105. #include "shell/browser/extensions/electron_browser_context_keyed_service_factories.h"
  106. #include "shell/browser/extensions/electron_extensions_browser_client.h"
  107. #include "shell/common/extensions/electron_extensions_client.h"
  108. #endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  109. #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  110. #include "chrome/browser/spellchecker/spellcheck_factory.h" // nogncheck
  111. #endif
  112. #if BUILDFLAG(ENABLE_PLUGINS)
  113. #include "content/public/browser/plugin_service.h"
  114. #include "shell/common/plugin_info.h"
  115. #endif // BUILDFLAG(ENABLE_PLUGINS)
  116. namespace electron {
  117. namespace {
  118. #if BUILDFLAG(IS_LINUX)
  119. class LinuxUiGetterImpl : public ui::LinuxUiGetter {
  120. public:
  121. LinuxUiGetterImpl() = default;
  122. ~LinuxUiGetterImpl() override = default;
  123. ui::LinuxUiTheme* GetForWindow(aura::Window* window) override {
  124. return GetForProfile(nullptr);
  125. }
  126. ui::LinuxUiTheme* GetForProfile(Profile* profile) override {
  127. return ui::GetLinuxUiTheme(ui::SystemTheme::kGtk);
  128. }
  129. };
  130. #endif
  131. template <typename T>
  132. void Erase(T* container, typename T::iterator iter) {
  133. container->erase(iter);
  134. }
  135. #if BUILDFLAG(IS_WIN)
  136. int GetMinimumFontSize() {
  137. int min_font_size;
  138. base::StringToInt(l10n_util::GetStringUTF16(IDS_MINIMUM_UI_FONT_SIZE),
  139. &min_font_size);
  140. return min_font_size;
  141. }
  142. #endif
  143. std::u16string MediaStringProvider(media::MessageId id) {
  144. switch (id) {
  145. case media::DEFAULT_AUDIO_DEVICE_NAME:
  146. return u"Default";
  147. #if BUILDFLAG(IS_WIN)
  148. case media::COMMUNICATIONS_AUDIO_DEVICE_NAME:
  149. return u"Communications";
  150. #endif
  151. default:
  152. return std::u16string();
  153. }
  154. }
  155. #if BUILDFLAG(IS_LINUX)
  156. // GTK does not provide a way to check if current theme is dark, so we compare
  157. // the text and background luminosity to get a result.
  158. // This trick comes from FireFox.
  159. void UpdateDarkThemeSetting() {
  160. float bg = color_utils::GetRelativeLuminance(gtk::GetBgColor("GtkLabel"));
  161. float fg = color_utils::GetRelativeLuminance(gtk::GetFgColor("GtkLabel"));
  162. bool is_dark = fg > bg;
  163. // Pass it to NativeUi theme, which is used by the nativeTheme module and most
  164. // places in Electron.
  165. ui::NativeTheme::GetInstanceForNativeUi()->set_use_dark_colors(is_dark);
  166. // Pass it to Web Theme, to make "prefers-color-scheme" media query work.
  167. ui::NativeTheme::GetInstanceForWeb()->set_use_dark_colors(is_dark);
  168. }
  169. #endif
  170. } // namespace
  171. #if BUILDFLAG(IS_LINUX)
  172. class DarkThemeObserver : public ui::NativeThemeObserver {
  173. public:
  174. DarkThemeObserver() = default;
  175. // ui::NativeThemeObserver:
  176. void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override {
  177. UpdateDarkThemeSetting();
  178. }
  179. };
  180. #endif
  181. // static
  182. ElectronBrowserMainParts* ElectronBrowserMainParts::self_ = nullptr;
  183. ElectronBrowserMainParts::ElectronBrowserMainParts()
  184. : fake_browser_process_(std::make_unique<BrowserProcessImpl>()),
  185. browser_(std::make_unique<Browser>()),
  186. node_bindings_(
  187. NodeBindings::Create(NodeBindings::BrowserEnvironment::kBrowser)),
  188. electron_bindings_(
  189. std::make_unique<ElectronBindings>(node_bindings_->uv_loop())) {
  190. DCHECK(!self_) << "Cannot have two ElectronBrowserMainParts";
  191. self_ = this;
  192. }
  193. ElectronBrowserMainParts::~ElectronBrowserMainParts() = default;
  194. // static
  195. ElectronBrowserMainParts* ElectronBrowserMainParts::Get() {
  196. DCHECK(self_);
  197. return self_;
  198. }
  199. bool ElectronBrowserMainParts::SetExitCode(int code) {
  200. if (!exit_code_)
  201. return false;
  202. content::BrowserMainLoop::GetInstance()->SetResultCode(code);
  203. *exit_code_ = code;
  204. return true;
  205. }
  206. int ElectronBrowserMainParts::GetExitCode() const {
  207. return exit_code_.value_or(content::RESULT_CODE_NORMAL_EXIT);
  208. }
  209. int ElectronBrowserMainParts::PreEarlyInitialization() {
  210. field_trial_list_ = std::make_unique<base::FieldTrialList>();
  211. #if BUILDFLAG(IS_POSIX)
  212. HandleSIGCHLD();
  213. #endif
  214. #if BUILDFLAG(IS_LINUX)
  215. DetectOzonePlatform();
  216. ui::OzonePlatform::PreEarlyInitialization();
  217. #endif
  218. #if BUILDFLAG(IS_MAC)
  219. screen_ = std::make_unique<display::ScopedNativeScreen>();
  220. #endif
  221. ui::ColorProviderManager::Get().AppendColorProviderInitializer(
  222. base::BindRepeating(AddChromeColorMixers));
  223. return GetExitCode();
  224. }
  225. void ElectronBrowserMainParts::PostEarlyInitialization() {
  226. // A workaround was previously needed because there was no ThreadTaskRunner
  227. // set. If this check is failing we may need to re-add that workaround
  228. DCHECK(base::SingleThreadTaskRunner::HasCurrentDefault());
  229. // The ProxyResolverV8 has setup a complete V8 environment, in order to
  230. // avoid conflicts we only initialize our V8 environment after that.
  231. js_env_ = std::make_unique<JavascriptEnvironment>(node_bindings_->uv_loop());
  232. v8::HandleScope scope(js_env_->isolate());
  233. node_bindings_->Initialize(js_env_->isolate()->GetCurrentContext());
  234. // Create the global environment.
  235. node::Environment* env = node_bindings_->CreateEnvironment(
  236. js_env_->isolate()->GetCurrentContext(), js_env_->platform());
  237. node_env_ = std::make_unique<NodeEnvironment>(env);
  238. env->set_trace_sync_io(env->options()->trace_sync_io);
  239. // We do not want to crash the main process on unhandled rejections.
  240. env->options()->unhandled_rejections = "warn-with-error-code";
  241. // Add Electron extended APIs.
  242. electron_bindings_->BindTo(js_env_->isolate(), env->process_object());
  243. // Create explicit microtasks runner.
  244. js_env_->CreateMicrotasksRunner();
  245. // Wrap the uv loop with global env.
  246. node_bindings_->set_uv_env(env);
  247. // Load everything.
  248. node_bindings_->LoadEnvironment(env);
  249. // We already initialized the feature list in PreEarlyInitialization(), but
  250. // the user JS script would not have had a chance to alter the command-line
  251. // switches at that point. Lets reinitialize it here to pick up the
  252. // command-line changes.
  253. base::FeatureList::ClearInstanceForTesting();
  254. InitializeFeatureList();
  255. // Initialize field trials.
  256. InitializeFieldTrials();
  257. // Reinitialize logging now that the app has had a chance to set the app name
  258. // and/or user data directory.
  259. logging::InitElectronLogging(*base::CommandLine::ForCurrentProcess(),
  260. /* is_preinit = */ false);
  261. // Initialize after user script environment creation.
  262. fake_browser_process_->PostEarlyInitialization();
  263. }
  264. int ElectronBrowserMainParts::PreCreateThreads() {
  265. if (!views::LayoutProvider::Get()) {
  266. layout_provider_ = std::make_unique<views::LayoutProvider>();
  267. }
  268. // Fetch the system locale for Electron.
  269. #if BUILDFLAG(IS_MAC)
  270. fake_browser_process_->SetSystemLocale(GetCurrentSystemLocale());
  271. #else
  272. fake_browser_process_->SetSystemLocale(base::i18n::GetConfiguredLocale());
  273. #endif
  274. auto* command_line = base::CommandLine::ForCurrentProcess();
  275. std::string locale = command_line->GetSwitchValueASCII(::switches::kLang);
  276. #if BUILDFLAG(IS_MAC)
  277. // The browser process only wants to support the language Cocoa will use,
  278. // so force the app locale to be overridden with that value. This must
  279. // happen before the ResourceBundle is loaded
  280. if (locale.empty())
  281. l10n_util::OverrideLocaleWithCocoaLocale();
  282. #elif BUILDFLAG(IS_LINUX)
  283. // l10n_util::GetApplicationLocaleInternal uses g_get_language_names(),
  284. // which keys off of getenv("LC_ALL").
  285. // We must set this env first to make ui::ResourceBundle accept the custom
  286. // locale.
  287. auto env = base::Environment::Create();
  288. absl::optional<std::string> lc_all;
  289. if (!locale.empty()) {
  290. std::string str;
  291. if (env->GetVar("LC_ALL", &str))
  292. lc_all.emplace(std::move(str));
  293. env->SetVar("LC_ALL", locale.c_str());
  294. }
  295. #endif
  296. // Load resources bundle according to locale.
  297. std::string loaded_locale = LoadResourceBundle(locale);
  298. #if defined(USE_AURA)
  299. // NB: must be called _after_ locale resource bundle is loaded,
  300. // because ui lib makes use of it in X11
  301. if (!display::Screen::GetScreen()) {
  302. screen_ = views::CreateDesktopScreen();
  303. }
  304. #endif
  305. // Initialize the app locale for Electron and Chromium.
  306. std::string app_locale = l10n_util::GetApplicationLocale(loaded_locale);
  307. ElectronBrowserClient::SetApplicationLocale(app_locale);
  308. fake_browser_process_->SetApplicationLocale(app_locale);
  309. #if BUILDFLAG(IS_LINUX)
  310. // Reset to the original LC_ALL since we should not be changing it.
  311. if (!locale.empty()) {
  312. if (lc_all)
  313. env->SetVar("LC_ALL", *lc_all);
  314. else
  315. env->UnSetVar("LC_ALL");
  316. }
  317. #endif
  318. // Force MediaCaptureDevicesDispatcher to be created on UI thread.
  319. MediaCaptureDevicesDispatcher::GetInstance();
  320. // Force MediaCaptureDevicesDispatcher to be created on UI thread.
  321. MediaCaptureDevicesDispatcher::GetInstance();
  322. #if BUILDFLAG(IS_MAC)
  323. ui::InitIdleMonitor();
  324. Browser::Get()->ApplyForcedRTL();
  325. #endif
  326. fake_browser_process_->PreCreateThreads();
  327. // Notify observers.
  328. Browser::Get()->PreCreateThreads();
  329. return 0;
  330. }
  331. void ElectronBrowserMainParts::PostCreateThreads() {
  332. content::GetIOThreadTaskRunner({})->PostTask(
  333. FROM_HERE,
  334. base::BindOnce(&tracing::TracingSamplerProfiler::CreateOnChildThread));
  335. #if BUILDFLAG(ENABLE_PLUGINS)
  336. // PluginService can only be used on the UI thread
  337. // and ContentClient::AddPlugins gets called for both browser and render
  338. // process where the latter will not have UI thread which leads to DCHECK.
  339. // Separate the WebPluginInfo registration for these processes.
  340. std::vector<content::WebPluginInfo> plugins;
  341. auto* plugin_service = content::PluginService::GetInstance();
  342. plugin_service->RefreshPlugins();
  343. GetInternalPlugins(&plugins);
  344. for (const auto& plugin : plugins)
  345. plugin_service->RegisterInternalPlugin(plugin, true);
  346. #endif
  347. }
  348. void ElectronBrowserMainParts::PostDestroyThreads() {
  349. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  350. extensions_browser_client_.reset();
  351. extensions::ExtensionsBrowserClient::Set(nullptr);
  352. #endif
  353. #if BUILDFLAG(IS_LINUX)
  354. device::BluetoothAdapterFactory::Shutdown();
  355. bluez::DBusBluezManagerWrapperLinux::Shutdown();
  356. #endif
  357. fake_browser_process_->PostDestroyThreads();
  358. }
  359. void ElectronBrowserMainParts::ToolkitInitialized() {
  360. #if BUILDFLAG(IS_LINUX)
  361. auto* linux_ui = ui::GetDefaultLinuxUi();
  362. CHECK(linux_ui);
  363. linux_ui_getter_ = std::make_unique<LinuxUiGetterImpl>();
  364. // Try loading gtk symbols used by Electron.
  365. electron::InitializeElectron_gtk(gtk::GetLibGtk());
  366. if (!electron::IsElectron_gtkInitialized()) {
  367. electron::UninitializeElectron_gtk();
  368. }
  369. electron::InitializeElectron_gdk_pixbuf(gtk::GetLibGdkPixbuf());
  370. CHECK(electron::IsElectron_gdk_pixbufInitialized())
  371. << "Failed to initialize libgdk_pixbuf-2.0.so.0";
  372. // Chromium does not respect GTK dark theme setting, but they may change
  373. // in future and this code might be no longer needed. Check the Chromium
  374. // issue to keep updated:
  375. // https://bugs.chromium.org/p/chromium/issues/detail?id=998903
  376. UpdateDarkThemeSetting();
  377. // Update the native theme when GTK theme changes. The GetNativeTheme
  378. // here returns a NativeThemeGtk, which monitors GTK settings.
  379. dark_theme_observer_ = std::make_unique<DarkThemeObserver>();
  380. auto* linux_ui_theme = ui::LinuxUiTheme::GetForProfile(nullptr);
  381. CHECK(linux_ui_theme);
  382. linux_ui_theme->GetNativeTheme()->AddObserver(dark_theme_observer_.get());
  383. ui::LinuxUi::SetInstance(linux_ui);
  384. // Cursor theme changes are tracked by LinuxUI (via a CursorThemeManager
  385. // implementation). Start observing them once it's initialized.
  386. ui::CursorFactory::GetInstance()->ObserveThemeChanges();
  387. #endif
  388. #if defined(USE_AURA)
  389. wm_state_ = std::make_unique<wm::WMState>();
  390. #endif
  391. #if BUILDFLAG(IS_WIN)
  392. gfx::win::SetAdjustFontCallback(&l10n_util::AdjustUiFont);
  393. gfx::win::SetGetMinimumFontSizeCallback(&GetMinimumFontSize);
  394. #endif
  395. #if BUILDFLAG(IS_MAC)
  396. views_delegate_ = std::make_unique<ViewsDelegateMac>();
  397. #else
  398. views_delegate_ = std::make_unique<ViewsDelegate>();
  399. #endif
  400. }
  401. int ElectronBrowserMainParts::PreMainMessageLoopRun() {
  402. // Run user's main script before most things get initialized, so we can have
  403. // a chance to setup everything.
  404. node_bindings_->PrepareEmbedThread();
  405. node_bindings_->StartPolling();
  406. // url::Add*Scheme are not threadsafe, this helps prevent data races.
  407. url::LockSchemeRegistries();
  408. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  409. extensions_client_ = std::make_unique<ElectronExtensionsClient>();
  410. extensions::ExtensionsClient::Set(extensions_client_.get());
  411. // BrowserContextKeyedAPIServiceFactories require an ExtensionsBrowserClient.
  412. extensions_browser_client_ =
  413. std::make_unique<ElectronExtensionsBrowserClient>();
  414. extensions::ExtensionsBrowserClient::Set(extensions_browser_client_.get());
  415. extensions::EnsureBrowserContextKeyedServiceFactoriesBuilt();
  416. extensions::electron::EnsureBrowserContextKeyedServiceFactoriesBuilt();
  417. #endif
  418. #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  419. SpellcheckServiceFactory::GetInstance();
  420. #endif
  421. content::WebUIControllerFactory::RegisterFactory(
  422. ElectronWebUIControllerFactory::GetInstance());
  423. auto* command_line = base::CommandLine::ForCurrentProcess();
  424. if (command_line->HasSwitch(switches::kRemoteDebuggingPipe)) {
  425. // --remote-debugging-pipe
  426. auto on_disconnect = base::BindOnce([]() {
  427. content::GetUIThreadTaskRunner({})->PostTask(
  428. FROM_HERE, base::BindOnce([]() { Browser::Get()->Quit(); }));
  429. });
  430. content::DevToolsAgentHost::StartRemoteDebuggingPipeHandler(
  431. std::move(on_disconnect));
  432. } else if (command_line->HasSwitch(switches::kRemoteDebuggingPort)) {
  433. // --remote-debugging-port
  434. DevToolsManagerDelegate::StartHttpHandler();
  435. }
  436. #if !BUILDFLAG(IS_MAC)
  437. // The corresponding call in macOS is in ElectronApplicationDelegate.
  438. Browser::Get()->WillFinishLaunching();
  439. Browser::Get()->DidFinishLaunching(base::Value::Dict());
  440. #endif
  441. // Notify observers that main thread message loop was initialized.
  442. Browser::Get()->PreMainMessageLoopRun();
  443. fake_browser_process_->PreMainMessageLoopRun();
  444. return GetExitCode();
  445. }
  446. void ElectronBrowserMainParts::WillRunMainMessageLoop(
  447. std::unique_ptr<base::RunLoop>& run_loop) {
  448. exit_code_ = content::RESULT_CODE_NORMAL_EXIT;
  449. Browser::Get()->SetMainMessageLoopQuitClosure(
  450. run_loop->QuitWhenIdleClosure());
  451. }
  452. void ElectronBrowserMainParts::PostCreateMainMessageLoop() {
  453. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
  454. std::string app_name = electron::Browser::Get()->GetName();
  455. #endif
  456. #if BUILDFLAG(IS_LINUX)
  457. auto shutdown_cb =
  458. base::BindOnce(base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
  459. ui::OzonePlatform::GetInstance()->PostCreateMainMessageLoop(
  460. std::move(shutdown_cb),
  461. content::GetUIThreadTaskRunner({content::BrowserTaskType::kUserInput}));
  462. bluez::DBusBluezManagerWrapperLinux::Initialize();
  463. // Set up crypt config. This needs to be done before anything starts the
  464. // network service, as the raw encryption key needs to be shared with the
  465. // network service for encrypted cookie storage.
  466. const base::CommandLine& command_line =
  467. *base::CommandLine::ForCurrentProcess();
  468. std::unique_ptr<os_crypt::Config> config =
  469. std::make_unique<os_crypt::Config>();
  470. // Forward to os_crypt the flag to use a specific password store.
  471. config->store = command_line.GetSwitchValueASCII(::switches::kPasswordStore);
  472. config->product_name = app_name;
  473. config->application_name = app_name;
  474. // c.f.
  475. // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/chrome_switches.cc;l=689;drc=9d82515060b9b75fa941986f5db7390299669ef1
  476. config->should_use_preference =
  477. command_line.HasSwitch(::switches::kEnableEncryptionSelection);
  478. base::PathService::Get(DIR_SESSION_DATA, &config->user_data_path);
  479. bool use_backend = !config->should_use_preference ||
  480. os_crypt::GetBackendUse(config->user_data_path);
  481. std::unique_ptr<base::Environment> env(base::Environment::Create());
  482. base::nix::DesktopEnvironment desktop_env =
  483. base::nix::GetDesktopEnvironment(env.get());
  484. os_crypt::SelectedLinuxBackend selected_backend =
  485. os_crypt::SelectBackend(config->store, use_backend, desktop_env);
  486. fake_browser_process_->SetLinuxStorageBackend(selected_backend);
  487. OSCrypt::SetConfig(std::move(config));
  488. #endif
  489. #if BUILDFLAG(IS_MAC)
  490. KeychainPassword::GetServiceName() = app_name + " Safe Storage";
  491. KeychainPassword::GetAccountName() = app_name;
  492. #endif
  493. #if BUILDFLAG(IS_POSIX)
  494. // Exit in response to SIGINT, SIGTERM, etc.
  495. InstallShutdownSignalHandlers(
  496. base::BindOnce(&Browser::Quit, base::Unretained(Browser::Get())),
  497. content::GetUIThreadTaskRunner({}));
  498. #endif
  499. }
  500. void ElectronBrowserMainParts::PostMainMessageLoopRun() {
  501. #if BUILDFLAG(IS_MAC)
  502. FreeAppDelegate();
  503. #endif
  504. // Shutdown the DownloadManager before destroying Node to prevent
  505. // DownloadItem callbacks from crashing.
  506. for (auto& iter : ElectronBrowserContext::browser_context_map()) {
  507. auto* download_manager = iter.second.get()->GetDownloadManager();
  508. if (download_manager) {
  509. download_manager->Shutdown();
  510. }
  511. }
  512. // Shutdown utility process created with Electron API before
  513. // stopping Node.js so that exit events can be emitted. We don't let
  514. // content layer perform this action since it destroys
  515. // child process only after this step (PostMainMessageLoopRun) via
  516. // BrowserProcessIOThread::ProcessHostCleanUp() which is too late for our
  517. // use case.
  518. // https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_main_loop.cc;l=1086-1108
  519. //
  520. // The following logic is based on
  521. // https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_process_io_thread.cc;l=127-159
  522. //
  523. // Although content::BrowserChildProcessHostIterator is only to be called from
  524. // IO thread, it is safe to call from PostMainMessageLoopRun because thread
  525. // restrictions have been lifted.
  526. // https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_main_loop.cc;l=1062-1078
  527. for (content::BrowserChildProcessHostIterator it(
  528. content::PROCESS_TYPE_UTILITY);
  529. !it.Done(); ++it) {
  530. if (it.GetDelegate()->GetServiceName() == node::mojom::NodeService::Name_) {
  531. auto& process = it.GetData().GetProcess();
  532. if (!process.IsValid())
  533. continue;
  534. auto utility_process_wrapper =
  535. api::UtilityProcessWrapper::FromProcessId(process.Pid());
  536. if (utility_process_wrapper)
  537. utility_process_wrapper->Shutdown(0 /* exit_code */);
  538. }
  539. }
  540. // Destroy node platform after all destructors_ are executed, as they may
  541. // invoke Node/V8 APIs inside them.
  542. node_env_->env()->set_trace_sync_io(false);
  543. js_env_->DestroyMicrotasksRunner();
  544. node::Stop(node_env_->env(), node::StopFlags::kDoNotTerminateIsolate);
  545. node_env_.reset();
  546. auto default_context_key = ElectronBrowserContext::PartitionKey("", false);
  547. std::unique_ptr<ElectronBrowserContext> default_context = std::move(
  548. ElectronBrowserContext::browser_context_map()[default_context_key]);
  549. ElectronBrowserContext::browser_context_map().clear();
  550. default_context.reset();
  551. fake_browser_process_->PostMainMessageLoopRun();
  552. content::DevToolsAgentHost::StopRemoteDebuggingPipeHandler();
  553. #if BUILDFLAG(IS_LINUX)
  554. ui::OzonePlatform::GetInstance()->PostMainMessageLoopRun();
  555. #endif
  556. }
  557. #if !BUILDFLAG(IS_MAC)
  558. void ElectronBrowserMainParts::PreCreateMainMessageLoop() {
  559. PreCreateMainMessageLoopCommon();
  560. }
  561. #endif
  562. void ElectronBrowserMainParts::PreCreateMainMessageLoopCommon() {
  563. #if BUILDFLAG(IS_MAC)
  564. InitializeMainNib();
  565. RegisterURLHandler();
  566. #endif
  567. media::SetLocalizedStringProvider(MediaStringProvider);
  568. #if BUILDFLAG(IS_WIN)
  569. auto* local_state = g_browser_process->local_state();
  570. DCHECK(local_state);
  571. bool os_crypt_init = OSCrypt::Init(local_state);
  572. DCHECK(os_crypt_init);
  573. #endif
  574. }
  575. device::mojom::GeolocationControl*
  576. ElectronBrowserMainParts::GetGeolocationControl() {
  577. if (!geolocation_control_) {
  578. content::GetDeviceService().BindGeolocationControl(
  579. geolocation_control_.BindNewPipeAndPassReceiver());
  580. }
  581. return geolocation_control_.get();
  582. }
  583. IconManager* ElectronBrowserMainParts::GetIconManager() {
  584. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  585. if (!icon_manager_.get())
  586. icon_manager_ = std::make_unique<IconManager>();
  587. return icon_manager_.get();
  588. }
  589. } // namespace electron