From c0a3c897cf70d0e856cca4a76cf28db1b05b2a42 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 2 Jul 2024 13:27:09 -0400 Subject: [PATCH] Remove main runner abstractions (see #3685) Remove code abstractions that are no longer required after deletion of the Alloy bootstrap. This is a functional no-op. --- BUILD.gn | 6 +- libcef/browser/main_runner.cc | 289 ++++++------------ libcef/browser/main_runner.h | 41 ++- libcef/browser/ui_thread.cc | 126 ++++++++ libcef/browser/ui_thread.h | 63 ++++ .../common/chrome/chrome_main_delegate_cef.cc | 3 +- .../common/chrome/chrome_main_delegate_cef.h | 16 +- .../chrome/chrome_main_runner_delegate.cc | 121 -------- .../chrome/chrome_main_runner_delegate.h | 59 ---- libcef/common/main_runner_delegate.h | 39 --- libcef/common/main_runner_handler.h | 24 -- 11 files changed, 323 insertions(+), 464 deletions(-) create mode 100644 libcef/browser/ui_thread.cc create mode 100644 libcef/browser/ui_thread.h delete mode 100644 libcef/common/chrome/chrome_main_runner_delegate.cc delete mode 100644 libcef/common/chrome/chrome_main_runner_delegate.h delete mode 100644 libcef/common/main_runner_delegate.h delete mode 100644 libcef/common/main_runner_handler.h diff --git a/BUILD.gn b/BUILD.gn index a59708260..f9e014aea 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -687,6 +687,8 @@ source_set("libcef_static") { "libcef/browser/trace_subscriber.cc", "libcef/browser/trace_subscriber.h", "libcef/browser/thread_util.h", + "libcef/browser/ui_thread.cc", + "libcef/browser/ui_thread.h", "libcef/browser/views/basic_label_button_impl.cc", "libcef/browser/views/basic_label_button_impl.h", "libcef/browser/views/basic_label_button_view.cc", @@ -768,8 +770,6 @@ source_set("libcef_static") { "libcef/common/chrome/chrome_content_client_cef.h", "libcef/common/chrome/chrome_main_delegate_cef.cc", "libcef/common/chrome/chrome_main_delegate_cef.h", - "libcef/common/chrome/chrome_main_runner_delegate.cc", - "libcef/common/chrome/chrome_main_runner_delegate.h", "libcef/common/command_line_impl.cc", "libcef/common/command_line_impl.h", "libcef/common/crash_reporter_client.cc", @@ -783,8 +783,6 @@ source_set("libcef_static") { "libcef/common/frame_util.h", "libcef/common/i18n_util_impl.cc", "libcef/common/json_impl.cc", - "libcef/common/main_runner_delegate.h", - "libcef/common/main_runner_handler.h", "libcef/common/net/http_header_utils.cc", "libcef/common/net/http_header_utils.h", "libcef/common/net/scheme_registration.cc", diff --git a/libcef/browser/main_runner.cc b/libcef/browser/main_runner.cc index 7302b2738..9334e02ef 100644 --- a/libcef/browser/main_runner.cc +++ b/libcef/browser/main_runner.cc @@ -5,40 +5,31 @@ #include "cef/libcef/browser/main_runner.h" -#include "base/at_exit.h" #include "base/base_switches.h" #include "base/command_line.h" #include "base/debug/debugger.h" #include "base/memory/raw_ptr.h" #include "base/run_loop.h" -#include "base/sequence_checker.h" -#include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" #include "cef/libcef/browser/browser_message_loop.h" +#include "cef/libcef/browser/chrome/chrome_content_browser_client_cef.h" #include "cef/libcef/browser/thread_util.h" +#include "cef/libcef/common/app_manager.h" #include "cef/libcef/common/cef_switches.h" -#include "cef/libcef/common/chrome/chrome_main_runner_delegate.h" +#include "chrome/browser/browser_process_impl.h" +#include "chrome/browser/chrome_process_singleton.h" #include "chrome/common/chrome_result_codes.h" #include "components/crash/core/app/crash_switches.h" +#include "components/keep_alive_registry/keep_alive_types.h" +#include "components/metrics/persistent_system_profile.h" #include "content/app/content_main_runner_impl.h" #include "content/browser/scheduler/browser_task_executor.h" #include "content/public/app/content_main.h" -#include "content/public/app/content_main_runner.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_switches.h" #include "third_party/crashpad/crashpad/handler/handler_main.h" -#if BUILDFLAG(IS_LINUX) -#include "ui/base/ozone_buildflags.h" -#if BUILDFLAG(IS_OZONE_X11) -#include "ui/ozone/platform/x11/ozone_platform_x11.h" -#endif -#endif - #if BUILDFLAG(IS_WIN) -#include - #include #include @@ -49,20 +40,7 @@ namespace { -enum class RuntimeType { - UNINITIALIZED, - CHROME, -}; -RuntimeType g_runtime_type = RuntimeType::UNINITIALIZED; - -std::unique_ptr MakeDelegate( - CefMainRunnerHandler* runner, - CefSettings* settings, - CefRefPtr application) { - g_runtime_type = RuntimeType::CHROME; - return std::make_unique(runner, settings, - application); -} +bool g_initialized = false; // Based on components/crash/core/app/run_as_crashpad_handler_win.cc // Remove the "--type=crashpad-handler" command-line flag that will otherwise @@ -110,148 +88,20 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line) { } // namespace -// Used to run the UI on a separate thread. -class CefUIThread : public base::PlatformThread::Delegate { - public: - CefUIThread(CefMainRunner* runner, base::OnceClosure setup_callback) - : runner_(runner), setup_callback_(std::move(setup_callback)) {} - ~CefUIThread() override { Stop(); } - - void Start() { - base::AutoLock lock(thread_lock_); - bool success = base::PlatformThread::CreateWithType( - 0, this, &thread_, base::ThreadType::kDefault); - if (!success) { - LOG(FATAL) << "failed to UI create thread"; - } - } - - void Stop() { - base::AutoLock lock(thread_lock_); - - if (!stopping_) { - stopping_ = true; - CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMainRunner::QuitMessageLoop, - base::Unretained(runner_))); - } - - // Can't join if the |thread_| is either already gone or is non-joinable. - if (thread_.is_null()) { - return; - } - - base::PlatformThread::Join(thread_); - thread_ = base::PlatformThreadHandle(); - - stopping_ = false; - } - - bool WaitUntilThreadStarted() const { - DCHECK(owning_sequence_checker_.CalledOnValidSequence()); - start_event_.Wait(); - return true; - } - - void InitializeBrowserRunner( - content::MainFunctionParams main_function_params) { -#if BUILDFLAG(IS_LINUX) -#if BUILDFLAG(IS_OZONE_X11) - // Disable creation of GtkUi (interface to GTK desktop features) and cause - // ui::GetDefaultLinuxUi() (and related functions) to return nullptr. We - // can't use GtkUi in combination with multi-threaded-message-loop because - // Chromium's GTK implementation doesn't use GDK threads. Light/dark theme - // changes will still be detected via DarkModeManagerLinux. - ui::SetMultiThreadedMessageLoopX11(); -#endif -#endif - - // Use our own browser process runner. - browser_runner_ = content::BrowserMainRunner::Create(); - - // Initialize browser process state. Uses the current thread's message loop. - int exit_code = - browser_runner_->Initialize(std::move(main_function_params)); - CHECK_EQ(exit_code, -1); - } - - void set_shutdown_callback(base::OnceClosure shutdown_callback) { - shutdown_callback_ = std::move(shutdown_callback); - } - - protected: - void ThreadMain() override { - base::PlatformThread::SetName("CefUIThread"); - -#if BUILDFLAG(IS_WIN) - // Initializes the COM library on the current thread. - CoInitialize(nullptr); -#endif - - start_event_.Signal(); - - std::move(setup_callback_).Run(); - - runner_->RunMessageLoop(); - - // Stop may be called before InitializeBrowserRunner if - // content::ContentMainRun was not successful (for example, due to process - // singleton relaunch). - if (browser_runner_) { - browser_runner_->Shutdown(); - browser_runner_.reset(); - } - - // This will be a no-op if there is no BrowserTaskExecutor. - content::BrowserTaskExecutor::Shutdown(); - - if (!shutdown_callback_.is_null()) { - std::move(shutdown_callback_).Run(); - } - - // Run exit callbacks on the UI thread to avoid sequence check failures. - base::AtExitManager::ProcessCallbacksNow(); - -#if BUILDFLAG(IS_WIN) - // Closes the COM library on the current thread. CoInitialize must - // be balanced by a corresponding call to CoUninitialize. - CoUninitialize(); -#endif - } - - const raw_ptr runner_; - base::OnceClosure setup_callback_; - base::OnceClosure shutdown_callback_; - - std::unique_ptr browser_runner_; - - bool stopping_ = false; - - // The thread's handle. - base::PlatformThreadHandle thread_; - mutable base::Lock thread_lock_; // Protects |thread_|. - - mutable base::WaitableEvent start_event_; - - // This class is not thread-safe, use this to verify access from the owning - // sequence of the Thread. - base::SequenceChecker owning_sequence_checker_; -}; - CefMainRunner::CefMainRunner(bool multi_threaded_message_loop, bool external_message_pump) : multi_threaded_message_loop_(multi_threaded_message_loop), external_message_pump_(external_message_pump) {} -CefMainRunner::~CefMainRunner() = default; - bool CefMainRunner::Initialize(CefSettings* settings, CefRefPtr application, const CefMainArgs& args, void* windows_sandbox_info, bool* initialized, base::OnceClosure context_initialized) { - DCHECK(!main_delegate_); - main_delegate_ = MakeDelegate(this, settings, application); + g_initialized = true; + settings_ = settings; + application_ = application; exit_code_ = ContentMainInitialize(args, windows_sandbox_info, &settings->no_sandbox); @@ -294,8 +144,6 @@ void CefMainRunner::Shutdown(base::OnceClosure shutdown_on_ui_thread, ui_thread_.reset(); } - main_delegate_->BeforeMainThreadShutdown(); - if (!multi_threaded_message_loop_) { // Main thread and UI thread are the same. StartShutdownOnUIThread(std::move(shutdown_on_ui_thread)); @@ -312,10 +160,14 @@ void CefMainRunner::Shutdown(base::OnceClosure shutdown_on_ui_thread, main_runner_.reset(); std::move(finalize_shutdown).Run(); - main_delegate_->AfterMainThreadShutdown(); main_delegate_.reset(); - g_runtime_type = RuntimeType::UNINITIALIZED; + sampling_profiler_.reset(); + keep_alive_.reset(); + settings_ = nullptr; + application_ = nullptr; + + g_initialized = false; } void CefMainRunner::RunMessageLoop() { @@ -324,7 +176,21 @@ void CefMainRunner::RunMessageLoop() { DCHECK(quit_callback_.is_null()); quit_callback_ = run_loop.QuitClosure(); - main_delegate_->BeforeMainMessageLoopRun(&run_loop); + // May be nullptr if content::ContentMainRun exits early. + if (g_browser_process) { + // The ScopedKeepAlive instance triggers shutdown logic when released on the + // UI thread before terminating the message loop (e.g. from + // CefQuitMessageLoop or FinishShutdownOnUIThread when running with + // multi-threaded message loop). + keep_alive_ = std::make_unique( + KeepAliveOrigin::APP_CONTROLLER, KeepAliveRestartOption::DISABLED); + + // The QuitClosure will be executed from BrowserProcessImpl::Unpin() via + // KeepAliveRegistry when the last ScopedKeepAlive is released. + // ScopedKeepAlives are also held by Browser objects. + static_cast(g_browser_process) + ->SetQuitClosure(run_loop.QuitClosure()); + } // Blocks until QuitMessageLoop() is called. run_loop.Run(); @@ -332,7 +198,7 @@ void CefMainRunner::RunMessageLoop() { void CefMainRunner::QuitMessageLoop() { if (!quit_callback_.is_null()) { - if (main_delegate_->HandleMainMessageLoopQuit()) { + if (HandleMainMessageLoopQuit()) { return; } std::move(quit_callback_).Run(); @@ -363,21 +229,18 @@ int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args, return -1; } - auto main_delegate = MakeDelegate( - /*runner=*/nullptr, /*settings=*/nullptr, application); - main_delegate->BeforeExecuteProcess(args); + g_initialized = true; - int result; + auto main_delegate = std::make_unique( + /*runner=*/nullptr, /*settings=*/nullptr, application); + BeforeMainInitialize(args); if (process_type == crash_reporter::switches::kCrashpadHandler) { - result = RunAsCrashpadHandler(command_line); - main_delegate->AfterExecuteProcess(); - return result; + return RunAsCrashpadHandler(command_line); } // Execute the secondary process. - content::ContentMainParams main_params( - main_delegate->GetContentMainDelegate()); + content::ContentMainParams main_params(main_delegate.get()); #if BUILDFLAG(IS_WIN) sandbox::SandboxInterfaceInfo sandbox_info = {nullptr}; if (windows_sandbox_info == nullptr) { @@ -392,22 +255,20 @@ int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args, main_params.argc = args.argc; main_params.argv = const_cast(args.argv); #endif - result = content::ContentMain(std::move(main_params)); - - main_delegate->AfterExecuteProcess(); - - return result; + return content::ContentMain(std::move(main_params)); } int CefMainRunner::ContentMainInitialize(const CefMainArgs& args, void* windows_sandbox_info, int* no_sandbox) { - main_delegate_->BeforeMainThreadInitialize(args); + BeforeMainInitialize(args); + + main_delegate_ = + std::make_unique(this, settings_, application_); // Initialize the content runner. main_runner_ = content::ContentMainRunner::Create(); - content::ContentMainParams main_params( - main_delegate_->GetContentMainDelegate()); + content::ContentMainParams main_params(main_delegate_.get()); #if BUILDFLAG(IS_WIN) sandbox::SandboxInterfaceInfo sandbox_info = {nullptr}; @@ -430,7 +291,12 @@ int CefMainRunner::ContentMainInitialize(const CefMainArgs& args, int CefMainRunner::ContentMainRun(bool* initialized, base::OnceClosure context_initialized) { - main_delegate_->BeforeMainThreadRun(multi_threaded_message_loop_); + if (multi_threaded_message_loop_) { + // Detach from the main thread so that these objects can be attached and + // modified from the UI thread going forward. + metrics::GlobalPersistentSystemProfile::GetInstance() + ->DetachFromCurrentThread(); + } int exit_code = -1; @@ -446,7 +312,7 @@ int CefMainRunner::ContentMainRun(bool* initialized, if (!CreateUIThread(base::BindOnce( [](CefMainRunner* runner, base::WaitableEvent* event, int* exit_code) { - runner->main_delegate_->BeforeUIThreadInitialize(); + runner->BeforeUIThreadInitialize(); *exit_code = content::ContentMainRun(runner->main_runner_.get()); if (*exit_code != content::RESULT_CODE_NORMAL_EXIT) { @@ -473,7 +339,7 @@ int CefMainRunner::ContentMainRun(bool* initialized, } } else { *initialized = true; - main_delegate_->BeforeUIThreadInitialize(); + BeforeUIThreadInitialize(); exit_code = content::ContentMainRun(main_runner_.get()); } @@ -493,6 +359,30 @@ int CefMainRunner::ContentMainRun(bool* initialized, return exit_code; } +// static +void CefMainRunner::BeforeMainInitialize(const CefMainArgs& args) { +#if BUILDFLAG(IS_WIN) + base::CommandLine::Init(0, nullptr); +#else + base::CommandLine::Init(args.argc, args.argv); +#endif +} + +bool CefMainRunner::HandleMainMessageLoopQuit() { + // May be nullptr if content::ContentMainRun exits early. + if (!g_browser_process) { + // Proceed with direct execution of the QuitClosure(). + return false; + } + + // May be called multiple times. See comments in RunMainMessageLoopBefore. + keep_alive_.reset(); + + // Cancel direct execution of the QuitClosure() in QuitMessageLoop. We + // instead wait for all Chrome browser windows to exit. + return true; +} + void CefMainRunner::PreBrowserMain() { if (external_message_pump_) { InitExternalMessagePumpFactoryForUI(); @@ -506,8 +396,7 @@ int CefMainRunner::RunMainProcess( browser_runner_ = content::BrowserMainRunner::Create(); // Initialize browser process state. Results in a call to - // AlloyBrowserMain::PreBrowserMain() which creates the UI message - // loop. + // PreBrowserMain() which creates the UI message loop. int exit_code = browser_runner_->Initialize(std::move(main_function_params)); if (exit_code >= 0) { @@ -539,7 +428,6 @@ void CefMainRunner::OnContextInitialized( base::OnceClosure context_initialized) { CEF_REQUIRE_UIT(); - main_delegate_->AfterUIThreadInitialize(); std::move(context_initialized).Run(); } @@ -561,18 +449,35 @@ void CefMainRunner::StartShutdownOnUIThread( ->ShutdownOnUIThread(); std::move(shutdown_on_ui_thread).Run(); - main_delegate_->BeforeUIThreadShutdown(); + BeforeUIThreadShutdown(); } void CefMainRunner::FinishShutdownOnUIThread() { - main_delegate_->AfterUIThreadShutdown(); + if (multi_threaded_message_loop_) { + // Don't wait for this to be called in ChromeMainDelegate::ProcessExiting. + // It is safe to call multiple times. + ChromeProcessSingleton::DeleteInstance(); + } +} + +void CefMainRunner::BeforeUIThreadInitialize() { + sampling_profiler_ = std::make_unique(); +} + +void CefMainRunner::BeforeUIThreadShutdown() { + static_cast( + CefAppManager::Get()->GetContentClient()->browser()) + ->CleanupOnUIThread(); + main_delegate_->CleanupOnUIThread(); + + sampling_profiler_.reset(); } // From libcef/features/runtime.h: namespace cef { bool IsChromeRuntimeEnabled() { - return g_runtime_type == RuntimeType::CHROME; + return g_initialized; } } // namespace cef diff --git a/libcef/browser/main_runner.h b/libcef/browser/main_runner.h index 6623a4f33..cb0b7c232 100644 --- a/libcef/browser/main_runner.h +++ b/libcef/browser/main_runner.h @@ -7,32 +7,30 @@ #define CEF_LIBCEF_BROWSER_MAIN_RUNNER_H_ #pragma once +#include + #include "base/functional/callback.h" +#include "base/memory/raw_ptr.h" #include "cef/include/cef_app.h" -#include "cef/libcef/common/main_runner_delegate.h" -#include "cef/libcef/common/main_runner_handler.h" +#include "cef/libcef/browser/ui_thread.h" +#include "cef/libcef/common/chrome/chrome_main_delegate_cef.h" +#include "chrome/common/profiler/main_thread_stack_sampling_profiler.h" +#include "components/keep_alive_registry/scoped_keep_alive.h" +#include "content/public/app/content_main_runner.h" #include "content/public/browser/browser_main_runner.h" namespace base { class WaitableEvent; } -namespace content { -class ContentMainRunner; -} // namespace content - -class CefUIThread; - // Manages the main process lifespan and related objects. -class CefMainRunner : public CefMainRunnerHandler { +class CefMainRunner final { public: CefMainRunner(bool multi_threaded_message_loop, bool external_message_pump); CefMainRunner(const CefMainRunner&) = delete; CefMainRunner& operator=(const CefMainRunner&) = delete; - ~CefMainRunner() override; - // Called from CefContext::Initialize. bool Initialize(CefSettings* settings, CefRefPtr application, @@ -56,6 +54,10 @@ class CefMainRunner : public CefMainRunnerHandler { CefRefPtr application, void* windows_sandbox_info); + // Called from ChromeMainDelegateCef. + void PreBrowserMain(); + int RunMainProcess(content::MainFunctionParams main_function_params); + private: // Called from Initialize(). int ContentMainInitialize(const CefMainArgs& args, @@ -63,9 +65,8 @@ class CefMainRunner : public CefMainRunnerHandler { int* no_sandbox); int ContentMainRun(bool* initialized, base::OnceClosure context_initialized); - // CefMainRunnerHandler methods: - void PreBrowserMain() override; - int RunMainProcess(content::MainFunctionParams main_function_params) override; + static void BeforeMainInitialize(const CefMainArgs& args); + bool HandleMainMessageLoopQuit(); // Create the UI thread when running with multi-threaded message loop mode. bool CreateUIThread(base::OnceClosure setup_callback); @@ -81,10 +82,12 @@ class CefMainRunner : public CefMainRunnerHandler { // thread RunLoop has stopped and before running exit callbacks. void FinishShutdownOnUIThread(); + void BeforeUIThreadInitialize(); + void BeforeUIThreadShutdown(); + const bool multi_threaded_message_loop_; const bool external_message_pump_; - std::unique_ptr main_delegate_; std::unique_ptr main_runner_; std::unique_ptr browser_runner_; @@ -94,6 +97,14 @@ class CefMainRunner : public CefMainRunnerHandler { base::OnceClosure quit_callback_; int exit_code_ = -1; + + std::unique_ptr main_delegate_; + + std::unique_ptr sampling_profiler_; + std::unique_ptr keep_alive_; + + raw_ptr settings_ = nullptr; + CefRefPtr application_; }; #endif // CEF_LIBCEF_BROWSER_MAIN_RUNNER_H_ diff --git a/libcef/browser/ui_thread.cc b/libcef/browser/ui_thread.cc new file mode 100644 index 000000000..e2b62d036 --- /dev/null +++ b/libcef/browser/ui_thread.cc @@ -0,0 +1,126 @@ +// Copyright 2020 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cef/libcef/browser/ui_thread.h" + +#include "base/at_exit.h" +#include "base/logging.h" +#include "cef/libcef/browser/main_runner.h" +#include "cef/libcef/browser/thread_util.h" +#include "content/browser/scheduler/browser_task_executor.h" + +#if BUILDFLAG(IS_LINUX) +#include "ui/base/ozone_buildflags.h" +#if BUILDFLAG(IS_OZONE_X11) +#include "ui/ozone/platform/x11/ozone_platform_x11.h" +#endif +#endif + +#if BUILDFLAG(IS_WIN) +#include +#endif + +CefUIThread::CefUIThread(CefMainRunner* runner, + base::OnceClosure setup_callback) + : runner_(runner), setup_callback_(std::move(setup_callback)) {} + +CefUIThread::~CefUIThread() { + Stop(); +} + +void CefUIThread::Start() { + base::AutoLock lock(thread_lock_); + bool success = base::PlatformThread::CreateWithType( + 0, this, &thread_, base::ThreadType::kDefault); + if (!success) { + LOG(FATAL) << "failed to UI create thread"; + } +} + +void CefUIThread::Stop() { + base::AutoLock lock(thread_lock_); + + if (!stopping_) { + stopping_ = true; + CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMainRunner::QuitMessageLoop, + base::Unretained(runner_))); + } + + // Can't join if the |thread_| is either already gone or is non-joinable. + if (thread_.is_null()) { + return; + } + + base::PlatformThread::Join(thread_); + thread_ = base::PlatformThreadHandle(); + + stopping_ = false; +} + +bool CefUIThread::WaitUntilThreadStarted() const { + DCHECK(owning_sequence_checker_.CalledOnValidSequence()); + start_event_.Wait(); + return true; +} + +void CefUIThread::InitializeBrowserRunner( + content::MainFunctionParams main_function_params) { +#if BUILDFLAG(IS_LINUX) +#if BUILDFLAG(IS_OZONE_X11) + // Disable creation of GtkUi (interface to GTK desktop features) and cause + // ui::GetDefaultLinuxUi() (and related functions) to return nullptr. We + // can't use GtkUi in combination with multi-threaded-message-loop because + // Chromium's GTK implementation doesn't use GDK threads. Light/dark theme + // changes will still be detected via DarkModeManagerLinux. + ui::SetMultiThreadedMessageLoopX11(); +#endif +#endif + + // Use our own browser process runner. + browser_runner_ = content::BrowserMainRunner::Create(); + + // Initialize browser process state. Uses the current thread's message loop. + int exit_code = browser_runner_->Initialize(std::move(main_function_params)); + CHECK_EQ(exit_code, -1); +} + +void CefUIThread::ThreadMain() { + base::PlatformThread::SetName("CefUIThread"); + +#if BUILDFLAG(IS_WIN) + // Initializes the COM library on the current thread. + CoInitialize(nullptr); +#endif + + start_event_.Signal(); + + std::move(setup_callback_).Run(); + + runner_->RunMessageLoop(); + + // Stop may be called before InitializeBrowserRunner if + // content::ContentMainRun was not successful (for example, due to process + // singleton relaunch). + if (browser_runner_) { + browser_runner_->Shutdown(); + browser_runner_.reset(); + } + + // This will be a no-op if there is no BrowserTaskExecutor. + content::BrowserTaskExecutor::Shutdown(); + + if (!shutdown_callback_.is_null()) { + std::move(shutdown_callback_).Run(); + } + + // Run exit callbacks on the UI thread to avoid sequence check failures. + base::AtExitManager::ProcessCallbacksNow(); + +#if BUILDFLAG(IS_WIN) + // Closes the COM library on the current thread. CoInitialize must + // be balanced by a corresponding call to CoUninitialize. + CoUninitialize(); +#endif +} diff --git a/libcef/browser/ui_thread.h b/libcef/browser/ui_thread.h new file mode 100644 index 000000000..42886c820 --- /dev/null +++ b/libcef/browser/ui_thread.h @@ -0,0 +1,63 @@ +// Copyright 2020 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CEF_LIBCEF_BROWSER_UI_THREAD_H_ +#define CEF_LIBCEF_BROWSER_UI_THREAD_H_ +#pragma once + +#include + +#include "base/functional/callback_forward.h" +#include "base/memory/raw_ptr.h" +#include "base/sequence_checker.h" +#include "base/synchronization/lock.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/platform_thread.h" +#include "content/public/browser/browser_main_runner.h" +#include "content/public/common/main_function_params.h" + +class CefMainRunner; + +// Used to run the UI on a separate thread. +class CefUIThread final : public base::PlatformThread::Delegate { + public: + CefUIThread(CefMainRunner* runner, base::OnceClosure setup_callback); + ~CefUIThread() override; + + void Start(); + void Stop(); + + bool WaitUntilThreadStarted() const; + + void InitializeBrowserRunner( + content::MainFunctionParams main_function_params); + + void set_shutdown_callback(base::OnceClosure shutdown_callback) { + shutdown_callback_ = std::move(shutdown_callback); + } + + private: + void ThreadMain() override; + + const raw_ptr runner_; + base::OnceClosure setup_callback_; + base::OnceClosure shutdown_callback_; + + std::unique_ptr browser_runner_; + + bool stopping_ = false; + + // The thread's handle. + base::PlatformThreadHandle thread_; + mutable base::Lock thread_lock_; // Protects |thread_|. + + mutable base::WaitableEvent start_event_; + + // This class is not thread-safe, use this to verify access from the owning + // sequence of the Thread. + base::SequenceChecker owning_sequence_checker_; +}; + +#endif // CEF_LIBCEF_BROWSER_UI_THREAD_H_ diff --git a/libcef/common/chrome/chrome_main_delegate_cef.cc b/libcef/common/chrome/chrome_main_delegate_cef.cc index 5212cc35c..8761d53e5 100644 --- a/libcef/common/chrome/chrome_main_delegate_cef.cc +++ b/libcef/common/chrome/chrome_main_delegate_cef.cc @@ -14,6 +14,7 @@ #include "base/threading/threading_features.h" #include "cef/libcef/browser/chrome/chrome_browser_context.h" #include "cef/libcef/browser/chrome/chrome_content_browser_client_cef.h" +#include "cef/libcef/browser/main_runner.h" #include "cef/libcef/common/cef_switches.h" #include "cef/libcef/common/command_line_impl.h" #include "cef/libcef/common/crash_reporting.h" @@ -114,7 +115,7 @@ void InitLogging(const base::CommandLine* command_line) { } // namespace -ChromeMainDelegateCef::ChromeMainDelegateCef(CefMainRunnerHandler* runner, +ChromeMainDelegateCef::ChromeMainDelegateCef(CefMainRunner* runner, CefSettings* settings, CefRefPtr application) : ChromeMainDelegate(base::TimeTicks::Now()), diff --git a/libcef/common/chrome/chrome_main_delegate_cef.h b/libcef/common/chrome/chrome_main_delegate_cef.h index 0a6da86c1..bec7c15a2 100644 --- a/libcef/common/chrome/chrome_main_delegate_cef.h +++ b/libcef/common/chrome/chrome_main_delegate_cef.h @@ -12,11 +12,11 @@ #include "cef/include/cef_app.h" #include "cef/libcef/common/app_manager.h" #include "cef/libcef/common/chrome/chrome_content_client_cef.h" -#include "cef/libcef/common/main_runner_handler.h" #include "cef/libcef/common/resource_bundle_delegate.h" #include "cef/libcef/common/task_runner_manager.h" #include "chrome/app/chrome_main_delegate.h" +class CefMainRunner; class ChromeContentBrowserClientCef; class ChromeContentRendererClientCef; @@ -27,7 +27,7 @@ class ChromeMainDelegateCef : public ChromeMainDelegate, public: // |runner| will be non-nullptr for the main process only, and will outlive // this object. - ChromeMainDelegateCef(CefMainRunnerHandler* runner, + ChromeMainDelegateCef(CefMainRunner* runner, CefSettings* settings, CefRefPtr application); @@ -36,6 +36,7 @@ class ChromeMainDelegateCef : public ChromeMainDelegate, ~ChromeMainDelegateCef() override; + protected: // ChromeMainDelegate overrides. std::optional BasicStartupComplete() override; void PreSandboxStartup() override; @@ -51,8 +52,10 @@ class ChromeMainDelegateCef : public ChromeMainDelegate, content::ContentClient* CreateContentClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; + ui::ResourceBundle::Delegate* GetResourceBundleDelegate() override { + return &resource_bundle_delegate_; + } - protected: // CefAppManager overrides. CefRefPtr GetApplication() override { return application_; } content::ContentClient* GetContentClient() override { @@ -73,16 +76,11 @@ class ChromeMainDelegateCef : public ChromeMainDelegate, scoped_refptr GetRenderTaskRunner() override; scoped_refptr GetWebWorkerTaskRunner() override; - // ChromeMainDelegate overrides. - ui::ResourceBundle::Delegate* GetResourceBundleDelegate() override { - return &resource_bundle_delegate_; - } - private: ChromeContentBrowserClientCef* content_browser_client() const; ChromeContentRendererClientCef* content_renderer_client() const; - const raw_ptr runner_; + const raw_ptr runner_; const raw_ptr settings_; CefRefPtr application_; diff --git a/libcef/common/chrome/chrome_main_runner_delegate.cc b/libcef/common/chrome/chrome_main_runner_delegate.cc deleted file mode 100644 index 80c35d5d8..000000000 --- a/libcef/common/chrome/chrome_main_runner_delegate.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2020 The Chromium Embedded Framework Authors. -// Portions copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cef/libcef/common/chrome/chrome_main_runner_delegate.h" - -#include "base/command_line.h" -#include "base/run_loop.h" -#include "cef/libcef/browser/chrome/chrome_content_browser_client_cef.h" -#include "cef/libcef/common/app_manager.h" -#include "cef/libcef/common/chrome/chrome_main_delegate_cef.h" -#include "chrome/browser/browser_process_impl.h" -#include "chrome/browser/chrome_process_singleton.h" -#include "chrome/common/profiler/main_thread_stack_sampling_profiler.h" -#include "components/keep_alive_registry/keep_alive_types.h" -#include "components/keep_alive_registry/scoped_keep_alive.h" -#include "components/metrics/persistent_system_profile.h" - -ChromeMainRunnerDelegate::ChromeMainRunnerDelegate( - CefMainRunnerHandler* runner, - CefSettings* settings, - CefRefPtr application) - : runner_(runner), settings_(settings), application_(application) {} - -ChromeMainRunnerDelegate::~ChromeMainRunnerDelegate() = default; - -content::ContentMainDelegate* -ChromeMainRunnerDelegate::GetContentMainDelegate() { - if (!main_delegate_) { - main_delegate_ = std::make_unique(runner_, settings_, - application_); - } - return main_delegate_.get(); -} - -void ChromeMainRunnerDelegate::BeforeMainThreadInitialize( - const CefMainArgs& args) { -#if BUILDFLAG(IS_WIN) - base::CommandLine::Init(0, nullptr); -#else - base::CommandLine::Init(args.argc, args.argv); -#endif -} - -void ChromeMainRunnerDelegate::BeforeMainThreadRun( - bool multi_threaded_message_loop) { - if (multi_threaded_message_loop) { - multi_threaded_message_loop_ = true; - - // Detach from the main thread so that these objects can be attached and - // modified from the UI thread going forward. - metrics::GlobalPersistentSystemProfile::GetInstance() - ->DetachFromCurrentThread(); - } -} - -void ChromeMainRunnerDelegate::BeforeMainMessageLoopRun( - base::RunLoop* run_loop) { - // May be nullptr if content::ContentMainRun exits early. - if (!g_browser_process) { - return; - } - - // The ScopedKeepAlive instance triggers shutdown logic when released on the - // UI thread before terminating the message loop (e.g. from CefQuitMessageLoop - // or FinishShutdownOnUIThread when running with multi-threaded message loop). - keep_alive_ = std::make_unique( - KeepAliveOrigin::APP_CONTROLLER, KeepAliveRestartOption::DISABLED); - - // The QuitClosure will be executed from BrowserProcessImpl::Unpin() via - // KeepAliveRegistry when the last ScopedKeepAlive is released. - // ScopedKeepAlives are also held by Browser objects. - static_cast(g_browser_process) - ->SetQuitClosure(run_loop->QuitClosure()); -} - -bool ChromeMainRunnerDelegate::HandleMainMessageLoopQuit() { - // May be nullptr if content::ContentMainRun exits early. - if (!g_browser_process) { - // Proceed with direct execution of the QuitClosure(). - return false; - } - - // May be called multiple times. See comments in RunMainMessageLoopBefore. - keep_alive_.reset(); - - // Cancel direct execution of the QuitClosure() in - // CefMainRunner::QuitMessageLoop. We instead wait for all Chrome browser - // windows to exit. - return true; -} - -void ChromeMainRunnerDelegate::BeforeUIThreadInitialize() { - sampling_profiler_ = std::make_unique(); -} - -void ChromeMainRunnerDelegate::BeforeUIThreadShutdown() { - static_cast( - CefAppManager::Get()->GetContentClient()->browser()) - ->CleanupOnUIThread(); - main_delegate_->CleanupOnUIThread(); - - sampling_profiler_.reset(); -} - -void ChromeMainRunnerDelegate::AfterUIThreadShutdown() { - if (multi_threaded_message_loop_) { - // Don't wait for this to be called in ChromeMainDelegate::ProcessExiting. - // It is safe to call multiple times. - ChromeProcessSingleton::DeleteInstance(); - } -} - -void ChromeMainRunnerDelegate::BeforeExecuteProcess(const CefMainArgs& args) { - BeforeMainThreadInitialize(args); -} - -void ChromeMainRunnerDelegate::AfterExecuteProcess() { - AfterMainThreadShutdown(); -} diff --git a/libcef/common/chrome/chrome_main_runner_delegate.h b/libcef/common/chrome/chrome_main_runner_delegate.h deleted file mode 100644 index f7c084d4a..000000000 --- a/libcef/common/chrome/chrome_main_runner_delegate.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2020 The Chromium Embedded Framework Authors. -// Portions copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_RUNNER_DELEGATE_CEF_ -#define CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_RUNNER_DELEGATE_CEF_ - -#include - -#include "base/memory/raw_ptr.h" -#include "cef/include/cef_app.h" -#include "cef/libcef/common/main_runner_delegate.h" -#include "cef/libcef/common/main_runner_handler.h" - -class ChromeMainDelegateCef; -class MainThreadStackSamplingProfiler; -class ScopedKeepAlive; - -class ChromeMainRunnerDelegate : public CefMainRunnerDelegate { - public: - // |runner| will be non-nullptr for the main process only, and will outlive - // this object. - ChromeMainRunnerDelegate(CefMainRunnerHandler* runner, - CefSettings* settings, - CefRefPtr application); - - ChromeMainRunnerDelegate(const ChromeMainRunnerDelegate&) = delete; - ChromeMainRunnerDelegate& operator=(const ChromeMainRunnerDelegate&) = delete; - - ~ChromeMainRunnerDelegate() override; - - protected: - // CefMainRunnerDelegate overrides. - content::ContentMainDelegate* GetContentMainDelegate() override; - void BeforeMainThreadInitialize(const CefMainArgs& args) override; - void BeforeMainThreadRun(bool multi_threaded_message_loop) override; - void BeforeMainMessageLoopRun(base::RunLoop* run_loop) override; - bool HandleMainMessageLoopQuit() override; - void BeforeUIThreadInitialize() override; - void BeforeUIThreadShutdown() override; - void AfterUIThreadShutdown() override; - void BeforeExecuteProcess(const CefMainArgs& args) override; - void AfterExecuteProcess() override; - - private: - std::unique_ptr main_delegate_; - - std::unique_ptr sampling_profiler_; - std::unique_ptr keep_alive_; - - const raw_ptr runner_; - const raw_ptr settings_; - CefRefPtr application_; - - bool multi_threaded_message_loop_ = false; -}; - -#endif // CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_RUNNER_DELEGATE_CEF_ diff --git a/libcef/common/main_runner_delegate.h b/libcef/common/main_runner_delegate.h deleted file mode 100644 index 11450aef0..000000000 --- a/libcef/common/main_runner_delegate.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CEF_LIBCEF_COMMON_MAIN_RUNNER_DELEGATE_H_ -#define CEF_LIBCEF_COMMON_MAIN_RUNNER_DELEGATE_H_ -#pragma once - -#include "cef/include/cef_app.h" - -namespace base { -class RunLoop; -} - -namespace content { -class ContentMainDelegate; -} - -class CefMainRunnerDelegate { - public: - virtual content::ContentMainDelegate* GetContentMainDelegate() = 0; - - virtual void BeforeMainThreadInitialize(const CefMainArgs& args) {} - virtual void BeforeMainThreadRun(bool multi_threaded_message_loop) {} - virtual void BeforeMainMessageLoopRun(base::RunLoop* run_loop) {} - virtual bool HandleMainMessageLoopQuit() { return false; } - virtual void BeforeUIThreadInitialize() {} - virtual void AfterUIThreadInitialize() {} - virtual void BeforeUIThreadShutdown() {} - virtual void AfterUIThreadShutdown() {} - virtual void BeforeMainThreadShutdown() {} - virtual void AfterMainThreadShutdown() {} - virtual void BeforeExecuteProcess(const CefMainArgs& args) {} - virtual void AfterExecuteProcess() {} - - virtual ~CefMainRunnerDelegate() = default; -}; - -#endif // CEF_LIBCEF_COMMON_MAIN_RUNNER_DELEGATE_H_ diff --git a/libcef/common/main_runner_handler.h b/libcef/common/main_runner_handler.h deleted file mode 100644 index fcb6a66c2..000000000 --- a/libcef/common/main_runner_handler.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CEF_LIBCEF_COMMON_MAIN_RUNNER_HANDLER_H_ -#define CEF_LIBCEF_COMMON_MAIN_RUNNER_HANDLER_H_ -#pragma once - -namespace content { -struct MainFunctionParams; -} - -// Handles running of the main process. -class CefMainRunnerHandler { - public: - virtual void PreBrowserMain() = 0; - virtual int RunMainProcess( - content::MainFunctionParams main_function_params) = 0; - - protected: - virtual ~CefMainRunnerHandler() = default; -}; - -#endif // CEF_LIBCEF_COMMON_MAIN_RUNNER_HANDLER_H_