Refactor process execution logic (see issue #2969)
CefContext implements the public CEF API functions and delegates the stages of content & service_manager process execution to CefMainRunner. CEF-specific runtime logic (which may be replaced with chrome-specific runtime logic) is then delegated to CefMainDelegate which implements content::ContentMainDelegate.
This commit is contained in:
parent
39aed35644
commit
049caf9131
2
BUILD.gn
2
BUILD.gn
|
@ -511,6 +511,8 @@ static_library("libcef_static") {
|
||||||
"libcef/browser/javascript_dialog_runner.h",
|
"libcef/browser/javascript_dialog_runner.h",
|
||||||
"libcef/browser/javascript_dialog_manager.cc",
|
"libcef/browser/javascript_dialog_manager.cc",
|
||||||
"libcef/browser/javascript_dialog_manager.h",
|
"libcef/browser/javascript_dialog_manager.h",
|
||||||
|
"libcef/browser/main_runner.cc",
|
||||||
|
"libcef/browser/main_runner.h",
|
||||||
"libcef/browser/media_capture_devices_dispatcher.cc",
|
"libcef/browser/media_capture_devices_dispatcher.cc",
|
||||||
"libcef/browser/media_capture_devices_dispatcher.h",
|
"libcef/browser/media_capture_devices_dispatcher.h",
|
||||||
"libcef/browser/media_router/media_route_impl.cc",
|
"libcef/browser/media_router/media_route_impl.cc",
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
// be found in the LICENSE file.
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
#include "libcef/browser/browser_message_loop.h"
|
#include "libcef/browser/browser_message_loop.h"
|
||||||
#include "libcef/browser/context.h"
|
|
||||||
#include "libcef/common/content_client.h"
|
#include "libcef/common/content_client.h"
|
||||||
|
|
||||||
#include "base/memory/ptr_util.h"
|
#include "base/memory/ptr_util.h"
|
||||||
|
@ -116,9 +115,6 @@ std::unique_ptr<base::MessagePump> MessagePumpFactoryForUI() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void InitMessagePumpFactoryForUI() {
|
void InitExternalMessagePumpFactoryForUI() {
|
||||||
const CefSettings& settings = CefContext::Get()->settings();
|
|
||||||
if (settings.external_message_pump) {
|
|
||||||
base::MessagePump::OverrideMessagePumpForUIFactory(MessagePumpFactoryForUI);
|
base::MessagePump::OverrideMessagePumpForUIFactory(MessagePumpFactoryForUI);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
#ifndef CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
|
#ifndef CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
|
||||||
#define CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
|
#define CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
|
||||||
|
|
||||||
void InitMessagePumpFactoryForUI();
|
void InitExternalMessagePumpFactoryForUI();
|
||||||
|
|
||||||
#endif // CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
|
#endif // CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
|
||||||
|
|
|
@ -62,7 +62,7 @@ void ChromeBrowserProcessStub::OnContextInitialized() {
|
||||||
context_initialized_ = true;
|
context_initialized_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChromeBrowserProcessStub::Shutdown() {
|
void ChromeBrowserProcessStub::CleanupOnUIThread() {
|
||||||
CEF_REQUIRE_UIT();
|
CEF_REQUIRE_UIT();
|
||||||
DCHECK(initialized_);
|
DCHECK(initialized_);
|
||||||
DCHECK(context_initialized_);
|
DCHECK(context_initialized_);
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ChromeBrowserProcessStub : public BrowserProcess {
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
void OnContextInitialized();
|
void OnContextInitialized();
|
||||||
void Shutdown();
|
void CleanupOnUIThread();
|
||||||
|
|
||||||
// BrowserProcess implementation.
|
// BrowserProcess implementation.
|
||||||
void EndSession() override;
|
void EndSession() override;
|
||||||
|
|
|
@ -3,34 +3,20 @@
|
||||||
// be found in the LICENSE file.
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
#include "libcef/browser/context.h"
|
#include "libcef/browser/context.h"
|
||||||
#include "libcef/browser/browser_host_impl.h"
|
|
||||||
#include "libcef/browser/browser_info.h"
|
|
||||||
#include "libcef/browser/browser_info_manager.h"
|
#include "libcef/browser/browser_info_manager.h"
|
||||||
#include "libcef/browser/browser_main.h"
|
|
||||||
#include "libcef/browser/chrome_browser_process_stub.h"
|
|
||||||
#include "libcef/browser/thread_util.h"
|
#include "libcef/browser/thread_util.h"
|
||||||
#include "libcef/browser/trace_subscriber.h"
|
#include "libcef/browser/trace_subscriber.h"
|
||||||
#include "libcef/common/cef_switches.h"
|
#include "libcef/common/cef_switches.h"
|
||||||
#include "libcef/common/main_delegate.h"
|
|
||||||
#include "libcef/common/widevine_loader.h"
|
|
||||||
#include "libcef/renderer/content_renderer_client.h"
|
|
||||||
|
|
||||||
#include "base/base_switches.h"
|
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/command_line.h"
|
|
||||||
#include "base/debug/debugger.h"
|
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
|
#include "base/message_loop/message_loop_current.h"
|
||||||
#include "base/run_loop.h"
|
#include "base/run_loop.h"
|
||||||
#include "base/synchronization/waitable_event.h"
|
|
||||||
#include "base/threading/thread_restrictions.h"
|
#include "base/threading/thread_restrictions.h"
|
||||||
#include "components/network_session_configurator/common/network_switches.h"
|
#include "components/network_session_configurator/common/network_switches.h"
|
||||||
#include "content/app/content_service_manager_main_delegate.h"
|
|
||||||
#include "content/public/browser/notification_service.h"
|
#include "content/public/browser/notification_service.h"
|
||||||
#include "content/public/browser/notification_types.h"
|
#include "content/public/browser/notification_types.h"
|
||||||
#include "content/public/browser/render_process_host.h"
|
|
||||||
#include "content/public/common/content_switches.h"
|
|
||||||
#include "services/service_manager/embedder/main.h"
|
|
||||||
#include "ui/base/resource/resource_bundle.h"
|
|
||||||
#include "ui/base/ui_base_switches.h"
|
#include "ui/base/ui_base_switches.h"
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
|
@ -38,13 +24,6 @@
|
||||||
#include "chrome/chrome_elf/chrome_elf_main.h"
|
#include "chrome/chrome_elf/chrome_elf_main.h"
|
||||||
#include "chrome/install_static/initialize_from_primary_module.h"
|
#include "chrome/install_static/initialize_from_primary_module.h"
|
||||||
#include "components/crash/core/app/crashpad.h"
|
#include "components/crash/core/app/crashpad.h"
|
||||||
#include "content/public/app/sandbox_helper_win.h"
|
|
||||||
#include "sandbox/win/src/sandbox_types.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(OS_MACOSX) || defined(OS_WIN)
|
|
||||||
#include "components/crash/core/app/crash_switches.h"
|
|
||||||
#include "third_party/crashpad/crashpad/handler/handler_main.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -95,54 +74,6 @@ void InitCrashReporter() {
|
||||||
}
|
}
|
||||||
#endif // defined(OS_WIN)
|
#endif // defined(OS_WIN)
|
||||||
|
|
||||||
#if defined(OS_MACOSX) || defined(OS_WIN)
|
|
||||||
|
|
||||||
// Based on components/crash/core/app/run_as_crashpad_handler_win.cc
|
|
||||||
// Remove the "--type=crashpad-handler" command-line flag that will otherwise
|
|
||||||
// confuse the crashpad handler.
|
|
||||||
// Chrome uses an embedded crashpad handler on Windows only and imports this
|
|
||||||
// function via the existing "run_as_crashpad_handler" target defined in
|
|
||||||
// components/crash/core/app/BUILD.gn. CEF uses an embedded handler on both
|
|
||||||
// Windows and macOS so we define the function here instead of using the
|
|
||||||
// existing target (because we can't use that target on macOS).
|
|
||||||
int RunAsCrashpadHandler(const base::CommandLine& command_line) {
|
|
||||||
base::CommandLine::StringVector argv = command_line.argv();
|
|
||||||
const base::CommandLine::StringType process_type =
|
|
||||||
FILE_PATH_LITERAL("--type=");
|
|
||||||
argv.erase(
|
|
||||||
std::remove_if(argv.begin(), argv.end(),
|
|
||||||
[&process_type](const base::CommandLine::StringType& str) {
|
|
||||||
return base::StartsWith(str, process_type,
|
|
||||||
base::CompareCase::SENSITIVE) ||
|
|
||||||
(!str.empty() && str[0] == L'/');
|
|
||||||
}),
|
|
||||||
argv.end());
|
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
|
||||||
// HandlerMain on macOS uses the system version of getopt_long which expects
|
|
||||||
// the first argument to be the program name.
|
|
||||||
argv.insert(argv.begin(), command_line.GetProgram().value());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::unique_ptr<char*[]> argv_as_utf8(new char*[argv.size() + 1]);
|
|
||||||
std::vector<std::string> storage;
|
|
||||||
storage.reserve(argv.size());
|
|
||||||
for (size_t i = 0; i < argv.size(); ++i) {
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
storage.push_back(base::UTF16ToUTF8(argv[i]));
|
|
||||||
#else
|
|
||||||
storage.push_back(argv[i]);
|
|
||||||
#endif
|
|
||||||
argv_as_utf8[i] = &storage[i][0];
|
|
||||||
}
|
|
||||||
argv_as_utf8[argv.size()] = nullptr;
|
|
||||||
argv.clear();
|
|
||||||
return crashpad::HandlerMain(static_cast<int>(storage.size()),
|
|
||||||
argv_as_utf8.get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // defined(OS_MACOSX) || defined(OS_WIN)
|
|
||||||
|
|
||||||
bool GetColor(const cef_color_t cef_in, bool is_windowless, SkColor* sk_out) {
|
bool GetColor(const cef_color_t cef_in, bool is_windowless, SkColor* sk_out) {
|
||||||
// Windowed browser colors must be fully opaque.
|
// Windowed browser colors must be fully opaque.
|
||||||
if (!is_windowless && CefColorGetA(cef_in) != SK_AlphaOPAQUE)
|
if (!is_windowless && CefColorGetA(cef_in) != SK_AlphaOPAQUE)
|
||||||
|
@ -252,52 +183,8 @@ int CefExecuteProcess(const CefMainArgs& args,
|
||||||
InitCrashReporter();
|
InitCrashReporter();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
|
return CefMainRunner::RunAsHelperProcess(args, application,
|
||||||
#if defined(OS_WIN)
|
windows_sandbox_info);
|
||||||
command_line.ParseFromString(::GetCommandLineW());
|
|
||||||
#else
|
|
||||||
command_line.InitFromArgv(args.argc, args.argv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Wait for the debugger as early in process initialization as possible.
|
|
||||||
if (command_line.HasSwitch(switches::kWaitForDebugger))
|
|
||||||
base::debug::WaitForDebugger(60, true);
|
|
||||||
|
|
||||||
// If no process type is specified then it represents the browser process and
|
|
||||||
// we do nothing.
|
|
||||||
std::string process_type =
|
|
||||||
command_line.GetSwitchValueASCII(switches::kProcessType);
|
|
||||||
if (process_type.empty())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#if defined(OS_MACOSX) || defined(OS_WIN)
|
|
||||||
if (process_type == crash_reporter::switches::kCrashpadHandler)
|
|
||||||
return RunAsCrashpadHandler(command_line);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CefMainDelegate main_delegate(application);
|
|
||||||
|
|
||||||
// Execute the secondary process.
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
|
||||||
if (windows_sandbox_info == nullptr) {
|
|
||||||
content::InitializeSandboxInfo(&sandbox_info);
|
|
||||||
windows_sandbox_info = &sandbox_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
content::ContentMainParams params(&main_delegate);
|
|
||||||
params.instance = args.instance;
|
|
||||||
params.sandbox_info =
|
|
||||||
static_cast<sandbox::SandboxInterfaceInfo*>(windows_sandbox_info);
|
|
||||||
|
|
||||||
return content::ContentMain(params);
|
|
||||||
#else
|
|
||||||
content::ContentMainParams params(&main_delegate);
|
|
||||||
params.argc = args.argc;
|
|
||||||
params.argv = const_cast<const char**>(args.argv);
|
|
||||||
|
|
||||||
return content::ContentMain(params);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CefInitialize(const CefMainArgs& args,
|
bool CefInitialize(const CefMainArgs& args,
|
||||||
|
@ -321,8 +208,6 @@ bool CefInitialize(const CefMainArgs& args,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_browser_process = new ChromeBrowserProcessStub();
|
|
||||||
|
|
||||||
// Create the new global context object.
|
// Create the new global context object.
|
||||||
g_context = new CefContext();
|
g_context = new CefContext();
|
||||||
|
|
||||||
|
@ -466,108 +351,25 @@ bool CefContext::Initialize(const CefMainArgs& args,
|
||||||
NormalizePathAndSet(settings_.resources_dir_path, "resources_dir_path");
|
NormalizePathAndSet(settings_.resources_dir_path, "resources_dir_path");
|
||||||
NormalizePathAndSet(settings_.locales_dir_path, "locales_dir_path");
|
NormalizePathAndSet(settings_.locales_dir_path, "locales_dir_path");
|
||||||
|
|
||||||
main_delegate_.reset(new CefMainDelegate(application));
|
|
||||||
browser_info_manager_.reset(new CefBrowserInfoManager);
|
browser_info_manager_.reset(new CefBrowserInfoManager);
|
||||||
|
|
||||||
int exit_code;
|
main_runner_.reset(new CefMainRunner(settings_.multi_threaded_message_loop,
|
||||||
|
settings_.external_message_pump));
|
||||||
// Initialize the content runner.
|
return main_runner_->Initialize(
|
||||||
content::ContentMainParams params(main_delegate_.get());
|
&settings_, application, args, windows_sandbox_info, &initialized_,
|
||||||
#if defined(OS_WIN)
|
base::BindOnce(&CefContext::OnContextInitialized,
|
||||||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
|
||||||
if (windows_sandbox_info == nullptr) {
|
|
||||||
windows_sandbox_info = &sandbox_info;
|
|
||||||
settings_.no_sandbox = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
params.instance = args.instance;
|
|
||||||
params.sandbox_info =
|
|
||||||
static_cast<sandbox::SandboxInterfaceInfo*>(windows_sandbox_info);
|
|
||||||
#else
|
|
||||||
params.argc = args.argc;
|
|
||||||
params.argv = const_cast<const char**>(args.argv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sm_main_delegate_.reset(
|
|
||||||
new content::ContentServiceManagerMainDelegate(params));
|
|
||||||
sm_main_params_.reset(
|
|
||||||
new service_manager::MainParams(sm_main_delegate_.get()));
|
|
||||||
|
|
||||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
|
||||||
sm_main_params_->argc = params.argc;
|
|
||||||
sm_main_params_->argv = params.argv;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
exit_code = service_manager::MainInitialize(*sm_main_params_);
|
|
||||||
DCHECK_LT(exit_code, 0);
|
|
||||||
if (exit_code >= 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static_cast<ChromeBrowserProcessStub*>(g_browser_process)->Initialize();
|
|
||||||
|
|
||||||
if (settings.multi_threaded_message_loop) {
|
|
||||||
base::WaitableEvent uithread_startup_event(
|
|
||||||
base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
|
||||||
base::WaitableEvent::InitialState::NOT_SIGNALED);
|
|
||||||
|
|
||||||
if (!main_delegate_->CreateUIThread(base::BindOnce(
|
|
||||||
[](CefContext* context, base::WaitableEvent* event) {
|
|
||||||
service_manager::MainRun(*context->sm_main_params_);
|
|
||||||
event->Signal();
|
|
||||||
},
|
|
||||||
base::Unretained(this),
|
|
||||||
base::Unretained(&uithread_startup_event)))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized_ = true;
|
|
||||||
|
|
||||||
// We need to wait until service_manager::MainRun has finished.
|
|
||||||
uithread_startup_event.Wait();
|
|
||||||
} else {
|
|
||||||
initialized_ = true;
|
|
||||||
service_manager::MainRun(*sm_main_params_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CEF_CURRENTLY_ON_UIT()) {
|
|
||||||
OnContextInitialized();
|
|
||||||
} else {
|
|
||||||
// Continue initialization on the UI thread.
|
|
||||||
CEF_POST_TASK(CEF_UIT, base::Bind(&CefContext::OnContextInitialized,
|
|
||||||
base::Unretained(this)));
|
base::Unretained(this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CefContext::Shutdown() {
|
void CefContext::Shutdown() {
|
||||||
// Must always be called on the same thread as Initialize.
|
// Must always be called on the same thread as Initialize.
|
||||||
DCHECK(OnInitThread());
|
DCHECK(OnInitThread());
|
||||||
|
|
||||||
shutting_down_ = true;
|
shutting_down_ = true;
|
||||||
|
|
||||||
if (settings_.multi_threaded_message_loop) {
|
main_runner_->Shutdown(
|
||||||
// Events that will be used to signal when shutdown is complete. Start in
|
base::BindOnce(&CefContext::ShutdownOnUIThread, base::Unretained(this)),
|
||||||
// non-signaled mode so that the event will block.
|
base::BindOnce(&CefContext::FinalizeShutdown, base::Unretained(this)));
|
||||||
base::WaitableEvent uithread_shutdown_event(
|
|
||||||
base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
|
||||||
base::WaitableEvent::InitialState::NOT_SIGNALED);
|
|
||||||
|
|
||||||
// Finish shutdown on the UI thread.
|
|
||||||
CEF_POST_TASK(CEF_UIT,
|
|
||||||
base::Bind(&CefContext::FinishShutdownOnUIThread,
|
|
||||||
base::Unretained(this), &uithread_shutdown_event));
|
|
||||||
|
|
||||||
/// Block until UI thread shutdown is complete.
|
|
||||||
uithread_shutdown_event.Wait();
|
|
||||||
|
|
||||||
FinalizeShutdown();
|
|
||||||
} else {
|
|
||||||
// Finish shutdown on the current thread, which should be the UI thread.
|
|
||||||
FinishShutdownOnUIThread(nullptr);
|
|
||||||
|
|
||||||
FinalizeShutdown();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CefContext::OnInitThread() {
|
bool CefContext::OnInitThread() {
|
||||||
|
@ -654,13 +456,6 @@ bool CefContext::HasObserver(Observer* observer) const {
|
||||||
void CefContext::OnContextInitialized() {
|
void CefContext::OnContextInitialized() {
|
||||||
CEF_REQUIRE_UIT();
|
CEF_REQUIRE_UIT();
|
||||||
|
|
||||||
static_cast<ChromeBrowserProcessStub*>(g_browser_process)
|
|
||||||
->OnContextInitialized();
|
|
||||||
|
|
||||||
#if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
|
|
||||||
CefWidevineLoader::GetInstance()->OnContextInitialized();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Notify the handler.
|
// Notify the handler.
|
||||||
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
|
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
|
||||||
if (app.get()) {
|
if (app.get()) {
|
||||||
|
@ -671,8 +466,7 @@ void CefContext::OnContextInitialized() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CefContext::FinishShutdownOnUIThread(
|
void CefContext::ShutdownOnUIThread() {
|
||||||
base::WaitableEvent* uithread_shutdown_event) {
|
|
||||||
CEF_REQUIRE_UIT();
|
CEF_REQUIRE_UIT();
|
||||||
|
|
||||||
browser_info_manager_->DestroyAllBrowsers();
|
browser_info_manager_->DestroyAllBrowsers();
|
||||||
|
@ -682,34 +476,8 @@ void CefContext::FinishShutdownOnUIThread(
|
||||||
|
|
||||||
if (trace_subscriber_.get())
|
if (trace_subscriber_.get())
|
||||||
trace_subscriber_.reset(nullptr);
|
trace_subscriber_.reset(nullptr);
|
||||||
|
|
||||||
static_cast<ChromeBrowserProcessStub*>(g_browser_process)->Shutdown();
|
|
||||||
|
|
||||||
ui::ResourceBundle::GetSharedInstance().CleanupOnUIThread();
|
|
||||||
|
|
||||||
sm_main_delegate_->ShutdownOnUIThread();
|
|
||||||
|
|
||||||
if (uithread_shutdown_event)
|
|
||||||
uithread_shutdown_event->Signal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CefContext::FinalizeShutdown() {
|
void CefContext::FinalizeShutdown() {
|
||||||
if (content::RenderProcessHost::run_renderer_in_process()) {
|
|
||||||
// Blocks until RenderProcess cleanup is complete.
|
|
||||||
CefContentRendererClient::Get()->RunSingleProcessCleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shut down the browser runner or UI thread.
|
|
||||||
main_delegate_->ShutdownBrowser();
|
|
||||||
|
|
||||||
// Shut down the content runner.
|
|
||||||
service_manager::MainShutdown(*sm_main_params_);
|
|
||||||
|
|
||||||
browser_info_manager_.reset(nullptr);
|
browser_info_manager_.reset(nullptr);
|
||||||
sm_main_params_.reset(nullptr);
|
|
||||||
sm_main_delegate_.reset(nullptr);
|
|
||||||
main_delegate_.reset(nullptr);
|
|
||||||
|
|
||||||
delete g_browser_process;
|
|
||||||
g_browser_process = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,26 +11,14 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "include/cef_app.h"
|
#include "include/cef_app.h"
|
||||||
|
#include "libcef/browser/main_runner.h"
|
||||||
|
|
||||||
#include "base/observer_list.h"
|
#include "base/observer_list.h"
|
||||||
#include "base/threading/platform_thread.h"
|
#include "base/threading/platform_thread.h"
|
||||||
#include "third_party/skia/include/core/SkColor.h"
|
#include "third_party/skia/include/core/SkColor.h"
|
||||||
|
|
||||||
namespace base {
|
|
||||||
class WaitableEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace content {
|
|
||||||
class ContentServiceManagerMainDelegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace service_manager {
|
|
||||||
struct MainParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CefBrowserHostImpl;
|
class CefBrowserHostImpl;
|
||||||
class CefBrowserInfoManager;
|
class CefBrowserInfoManager;
|
||||||
class CefMainDelegate;
|
|
||||||
class CefTraceSubscriber;
|
class CefTraceSubscriber;
|
||||||
|
|
||||||
class CefContext {
|
class CefContext {
|
||||||
|
@ -105,7 +93,7 @@ class CefContext {
|
||||||
|
|
||||||
// Performs shutdown actions that need to occur on the UI thread before any
|
// Performs shutdown actions that need to occur on the UI thread before any
|
||||||
// threads are destroyed.
|
// threads are destroyed.
|
||||||
void FinishShutdownOnUIThread(base::WaitableEvent* uithread_shutdown_event);
|
void ShutdownOnUIThread();
|
||||||
|
|
||||||
// Destroys the main runner and related objects.
|
// Destroys the main runner and related objects.
|
||||||
void FinalizeShutdown();
|
void FinalizeShutdown();
|
||||||
|
@ -119,9 +107,7 @@ class CefContext {
|
||||||
|
|
||||||
CefSettings settings_;
|
CefSettings settings_;
|
||||||
|
|
||||||
std::unique_ptr<CefMainDelegate> main_delegate_;
|
std::unique_ptr<CefMainRunner> main_runner_;
|
||||||
std::unique_ptr<content::ContentServiceManagerMainDelegate> sm_main_delegate_;
|
|
||||||
std::unique_ptr<service_manager::MainParams> sm_main_params_;
|
|
||||||
std::unique_ptr<CefTraceSubscriber> trace_subscriber_;
|
std::unique_ptr<CefTraceSubscriber> trace_subscriber_;
|
||||||
std::unique_ptr<CefBrowserInfoManager> browser_info_manager_;
|
std::unique_ptr<CefBrowserInfoManager> browser_info_manager_;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,489 @@
|
||||||
|
// 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 "libcef/browser/main_runner.h"
|
||||||
|
|
||||||
|
#include "libcef/browser/browser_message_loop.h"
|
||||||
|
#include "libcef/browser/thread_util.h"
|
||||||
|
#include "libcef/renderer/content_renderer_client.h"
|
||||||
|
|
||||||
|
#include "base/at_exit.h"
|
||||||
|
#include "base/base_switches.h"
|
||||||
|
#include "base/command_line.h"
|
||||||
|
#include "base/debug/debugger.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 "content/app/content_service_manager_main_delegate.h"
|
||||||
|
#include "content/browser/scheduler/browser_task_executor.h"
|
||||||
|
#include "content/public/browser/render_process_host.h"
|
||||||
|
#include "content/public/common/content_switches.h"
|
||||||
|
#include "services/service_manager/embedder/main.h"
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
#include <Objbase.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include "content/public/app/sandbox_helper_win.h"
|
||||||
|
#include "sandbox/win/src/sandbox_types.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
|
#include "components/crash/core/app/crash_switches.h"
|
||||||
|
#include "third_party/crashpad/crashpad/handler/handler_main.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
|
|
||||||
|
// Based on components/crash/core/app/run_as_crashpad_handler_win.cc
|
||||||
|
// Remove the "--type=crashpad-handler" command-line flag that will otherwise
|
||||||
|
// confuse the crashpad handler.
|
||||||
|
// Chrome uses an embedded crashpad handler on Windows only and imports this
|
||||||
|
// function via the existing "run_as_crashpad_handler" target defined in
|
||||||
|
// components/crash/core/app/BUILD.gn. CEF uses an embedded handler on both
|
||||||
|
// Windows and macOS so we define the function here instead of using the
|
||||||
|
// existing target (because we can't use that target on macOS).
|
||||||
|
int RunAsCrashpadHandler(const base::CommandLine& command_line) {
|
||||||
|
base::CommandLine::StringVector argv = command_line.argv();
|
||||||
|
const base::CommandLine::StringType process_type =
|
||||||
|
FILE_PATH_LITERAL("--type=");
|
||||||
|
argv.erase(
|
||||||
|
std::remove_if(argv.begin(), argv.end(),
|
||||||
|
[&process_type](const base::CommandLine::StringType& str) {
|
||||||
|
return base::StartsWith(str, process_type,
|
||||||
|
base::CompareCase::SENSITIVE) ||
|
||||||
|
(!str.empty() && str[0] == L'/');
|
||||||
|
}),
|
||||||
|
argv.end());
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
// HandlerMain on macOS uses the system version of getopt_long which expects
|
||||||
|
// the first argument to be the program name.
|
||||||
|
argv.insert(argv.begin(), command_line.GetProgram().value());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<char*[]> argv_as_utf8(new char*[argv.size() + 1]);
|
||||||
|
std::vector<std::string> storage;
|
||||||
|
storage.reserve(argv.size());
|
||||||
|
for (size_t i = 0; i < argv.size(); ++i) {
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
storage.push_back(base::UTF16ToUTF8(argv[i]));
|
||||||
|
#else
|
||||||
|
storage.push_back(argv[i]);
|
||||||
|
#endif
|
||||||
|
argv_as_utf8[i] = &storage[i][0];
|
||||||
|
}
|
||||||
|
argv_as_utf8[argv.size()] = nullptr;
|
||||||
|
argv.clear();
|
||||||
|
return crashpad::HandlerMain(static_cast<int>(storage.size()),
|
||||||
|
argv_as_utf8.get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Used to run the UI on a separate thread.
|
||||||
|
class CefUIThread : public base::PlatformThread::Delegate {
|
||||||
|
public:
|
||||||
|
explicit CefUIThread(base::OnceClosure setup_callback)
|
||||||
|
: setup_callback_(std::move(setup_callback)) {}
|
||||||
|
~CefUIThread() override { Stop(); }
|
||||||
|
|
||||||
|
void Start() {
|
||||||
|
base::AutoLock lock(thread_lock_);
|
||||||
|
bool success = base::PlatformThread::CreateWithPriority(
|
||||||
|
0, this, &thread_, base::ThreadPriority::NORMAL);
|
||||||
|
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(&CefUIThread::ThreadQuitHelper,
|
||||||
|
base::Unretained(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(
|
||||||
|
const content::MainFunctionParams& main_function_params) {
|
||||||
|
// 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(main_function_params);
|
||||||
|
CHECK_EQ(exit_code, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ThreadMain() override {
|
||||||
|
base::PlatformThread::SetName("CefUIThread");
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
// Initializes the COM library on the current thread.
|
||||||
|
CoInitialize(nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
start_event_.Signal();
|
||||||
|
|
||||||
|
std::move(setup_callback_).Run();
|
||||||
|
|
||||||
|
base::RunLoop run_loop;
|
||||||
|
run_loop_ = &run_loop;
|
||||||
|
run_loop.Run();
|
||||||
|
|
||||||
|
browser_runner_->Shutdown();
|
||||||
|
browser_runner_.reset(nullptr);
|
||||||
|
|
||||||
|
content::BrowserTaskExecutor::Shutdown();
|
||||||
|
|
||||||
|
// Run exit callbacks on the UI thread to avoid sequence check failures.
|
||||||
|
base::AtExitManager::ProcessCallbacksNow();
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
// Closes the COM library on the current thread. CoInitialize must
|
||||||
|
// be balanced by a corresponding call to CoUninitialize.
|
||||||
|
CoUninitialize();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
run_loop_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadQuitHelper() {
|
||||||
|
DCHECK(run_loop_);
|
||||||
|
run_loop_->QuitWhenIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
||||||
|
base::OnceClosure setup_callback_;
|
||||||
|
|
||||||
|
bool stopping_ = false;
|
||||||
|
|
||||||
|
// The thread's handle.
|
||||||
|
base::PlatformThreadHandle thread_;
|
||||||
|
mutable base::Lock thread_lock_; // Protects |thread_|.
|
||||||
|
|
||||||
|
base::RunLoop* run_loop_ = nullptr;
|
||||||
|
|
||||||
|
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<CefApp> application,
|
||||||
|
const CefMainArgs& args,
|
||||||
|
void* windows_sandbox_info,
|
||||||
|
bool* initialized,
|
||||||
|
base::OnceClosure context_initialized) {
|
||||||
|
CefRuntimeInitialize(settings, application);
|
||||||
|
|
||||||
|
const int exit_code =
|
||||||
|
ContentMainInitialize(args, windows_sandbox_info, &settings->no_sandbox);
|
||||||
|
if (exit_code >= 0) {
|
||||||
|
NOTREACHED() << "ContentMainInitialize failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ContentMainRun(initialized, std::move(context_initialized))) {
|
||||||
|
NOTREACHED() << "ContentMainRun failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefMainRunner::Shutdown(base::OnceClosure shutdown_on_ui_thread,
|
||||||
|
base::OnceClosure finalize_shutdown) {
|
||||||
|
if (multi_threaded_message_loop_) {
|
||||||
|
// Events that will be used to signal when shutdown is complete. Start in
|
||||||
|
// non-signaled mode so that the event will block.
|
||||||
|
base::WaitableEvent uithread_shutdown_event(
|
||||||
|
base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||||
|
base::WaitableEvent::InitialState::NOT_SIGNALED);
|
||||||
|
|
||||||
|
// Finish shutdown on the UI thread.
|
||||||
|
CEF_POST_TASK(
|
||||||
|
CEF_UIT,
|
||||||
|
base::BindOnce(&CefMainRunner::FinishShutdownOnUIThread,
|
||||||
|
base::Unretained(this), std::move(shutdown_on_ui_thread),
|
||||||
|
&uithread_shutdown_event));
|
||||||
|
|
||||||
|
/// Block until UI thread shutdown is complete.
|
||||||
|
uithread_shutdown_event.Wait();
|
||||||
|
|
||||||
|
FinalizeShutdown(std::move(finalize_shutdown));
|
||||||
|
} else {
|
||||||
|
// Finish shutdown on the current thread, which should be the UI thread.
|
||||||
|
FinishShutdownOnUIThread(std::move(shutdown_on_ui_thread), nullptr);
|
||||||
|
|
||||||
|
FinalizeShutdown(std::move(finalize_shutdown));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
|
||||||
|
CefRefPtr<CefApp> application,
|
||||||
|
void* windows_sandbox_info) {
|
||||||
|
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
command_line.ParseFromString(::GetCommandLineW());
|
||||||
|
#else
|
||||||
|
command_line.InitFromArgv(args.argc, args.argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Wait for the debugger as early in process initialization as possible.
|
||||||
|
if (command_line.HasSwitch(switches::kWaitForDebugger))
|
||||||
|
base::debug::WaitForDebugger(60, true);
|
||||||
|
|
||||||
|
// If no process type is specified then it represents the browser process and
|
||||||
|
// we do nothing.
|
||||||
|
const std::string& process_type =
|
||||||
|
command_line.GetSwitchValueASCII(switches::kProcessType);
|
||||||
|
if (process_type.empty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||||
|
if (process_type == crash_reporter::switches::kCrashpadHandler)
|
||||||
|
return RunAsCrashpadHandler(command_line);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<content::ContentMainDelegate> main_delegate;
|
||||||
|
main_delegate.reset(new CefMainDelegate(/*context=*/nullptr,
|
||||||
|
/*settings=*/nullptr, application));
|
||||||
|
|
||||||
|
// Execute the secondary process.
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||||
|
if (windows_sandbox_info == nullptr) {
|
||||||
|
content::InitializeSandboxInfo(&sandbox_info);
|
||||||
|
windows_sandbox_info = &sandbox_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
content::ContentMainParams params(main_delegate.get());
|
||||||
|
params.instance = args.instance;
|
||||||
|
params.sandbox_info =
|
||||||
|
static_cast<sandbox::SandboxInterfaceInfo*>(windows_sandbox_info);
|
||||||
|
|
||||||
|
return content::ContentMain(params);
|
||||||
|
#else
|
||||||
|
content::ContentMainParams params(main_delegate.get());
|
||||||
|
params.argc = args.argc;
|
||||||
|
params.argv = const_cast<const char**>(args.argv);
|
||||||
|
|
||||||
|
return content::ContentMain(params);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefMainRunner::CefRuntimeInitialize(CefSettings* settings,
|
||||||
|
CefRefPtr<CefApp> app) {
|
||||||
|
DCHECK_EQ(RuntimeType::UNINITIALIZED, runtime_type_);
|
||||||
|
DCHECK(!main_delegate_);
|
||||||
|
|
||||||
|
runtime_type_ = RuntimeType::CEF;
|
||||||
|
CefMainDelegate::CefInitialize();
|
||||||
|
main_delegate_.reset(new CefMainDelegate(this, settings, app));
|
||||||
|
}
|
||||||
|
|
||||||
|
int CefMainRunner::ContentMainInitialize(const CefMainArgs& args,
|
||||||
|
void* windows_sandbox_info,
|
||||||
|
int* no_sandbox) {
|
||||||
|
DCHECK(main_delegate_);
|
||||||
|
|
||||||
|
// Initialize the content runner.
|
||||||
|
content::ContentMainParams params(main_delegate_.get());
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||||
|
if (windows_sandbox_info == nullptr) {
|
||||||
|
windows_sandbox_info = &sandbox_info;
|
||||||
|
*no_sandbox = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.instance = args.instance;
|
||||||
|
params.sandbox_info =
|
||||||
|
static_cast<sandbox::SandboxInterfaceInfo*>(windows_sandbox_info);
|
||||||
|
#else
|
||||||
|
params.argc = args.argc;
|
||||||
|
params.argv = const_cast<const char**>(args.argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sm_main_delegate_.reset(
|
||||||
|
new content::ContentServiceManagerMainDelegate(params));
|
||||||
|
sm_main_params_.reset(
|
||||||
|
new service_manager::MainParams(sm_main_delegate_.get()));
|
||||||
|
|
||||||
|
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||||
|
sm_main_params_->argc = params.argc;
|
||||||
|
sm_main_params_->argv = params.argv;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return service_manager::MainInitialize(*sm_main_params_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefMainRunner::ContentMainRun(bool* initialized,
|
||||||
|
base::OnceClosure context_initialized) {
|
||||||
|
if (IsCefRuntime())
|
||||||
|
CefMainDelegate::MainThreadInitialize();
|
||||||
|
|
||||||
|
if (multi_threaded_message_loop_) {
|
||||||
|
base::WaitableEvent uithread_startup_event(
|
||||||
|
base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||||
|
base::WaitableEvent::InitialState::NOT_SIGNALED);
|
||||||
|
|
||||||
|
if (!CreateUIThread(base::BindOnce(
|
||||||
|
[](CefMainRunner* runner, base::WaitableEvent* event) {
|
||||||
|
service_manager::MainRun(*runner->sm_main_params_);
|
||||||
|
event->Signal();
|
||||||
|
},
|
||||||
|
base::Unretained(this),
|
||||||
|
base::Unretained(&uithread_startup_event)))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*initialized = true;
|
||||||
|
|
||||||
|
// We need to wait until service_manager::MainRun has finished.
|
||||||
|
uithread_startup_event.Wait();
|
||||||
|
} else {
|
||||||
|
*initialized = true;
|
||||||
|
service_manager::MainRun(*sm_main_params_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CEF_CURRENTLY_ON_UIT()) {
|
||||||
|
OnContextInitialized(std::move(context_initialized));
|
||||||
|
} else {
|
||||||
|
// Continue initialization on the UI thread.
|
||||||
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMainRunner::OnContextInitialized,
|
||||||
|
base::Unretained(this),
|
||||||
|
std::move(context_initialized)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefMainRunner::PreCreateMainMessageLoop() {
|
||||||
|
if (external_message_pump_) {
|
||||||
|
InitExternalMessagePumpFactoryForUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CefMainRunner::RunMainProcess(
|
||||||
|
const content::MainFunctionParams& main_function_params) {
|
||||||
|
if (!multi_threaded_message_loop_) {
|
||||||
|
// Use our own browser process runner.
|
||||||
|
browser_runner_ = content::BrowserMainRunner::Create();
|
||||||
|
|
||||||
|
// Initialize browser process state. Results in a call to
|
||||||
|
// CefBrowserMain::PreMainMessageLoopStart() which creates the UI message
|
||||||
|
// loop.
|
||||||
|
int exit_code = browser_runner_->Initialize(main_function_params);
|
||||||
|
if (exit_code >= 0)
|
||||||
|
return exit_code;
|
||||||
|
} else {
|
||||||
|
// Running on the separate UI thread.
|
||||||
|
DCHECK(ui_thread_);
|
||||||
|
ui_thread_->InitializeBrowserRunner(main_function_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefMainRunner::CreateUIThread(base::OnceClosure setup_callback) {
|
||||||
|
DCHECK(!ui_thread_);
|
||||||
|
|
||||||
|
ui_thread_.reset(new CefUIThread(std::move(setup_callback)));
|
||||||
|
ui_thread_->Start();
|
||||||
|
ui_thread_->WaitUntilThreadStarted();
|
||||||
|
|
||||||
|
if (external_message_pump_) {
|
||||||
|
InitExternalMessagePumpFactoryForUI();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefMainRunner::OnContextInitialized(
|
||||||
|
base::OnceClosure context_initialized) {
|
||||||
|
CEF_REQUIRE_UIT();
|
||||||
|
if (IsCefRuntime())
|
||||||
|
CefMainDelegate::UIThreadInitialize();
|
||||||
|
std::move(context_initialized).Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefMainRunner::FinishShutdownOnUIThread(
|
||||||
|
base::OnceClosure shutdown_on_ui_thread,
|
||||||
|
base::WaitableEvent* uithread_shutdown_event) {
|
||||||
|
CEF_REQUIRE_UIT();
|
||||||
|
|
||||||
|
sm_main_delegate_->ShutdownOnUIThread();
|
||||||
|
|
||||||
|
std::move(shutdown_on_ui_thread).Run();
|
||||||
|
if (IsCefRuntime())
|
||||||
|
CefMainDelegate::UIThreadShutdown();
|
||||||
|
|
||||||
|
if (uithread_shutdown_event)
|
||||||
|
uithread_shutdown_event->Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CefMainRunner::FinalizeShutdown(base::OnceClosure finalize_shutdown) {
|
||||||
|
if (content::RenderProcessHost::run_renderer_in_process() && IsCefRuntime()) {
|
||||||
|
// Blocks until RenderProcess cleanup is complete.
|
||||||
|
CefContentRendererClient::Get()->RunSingleProcessCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (browser_runner_.get()) {
|
||||||
|
browser_runner_->Shutdown();
|
||||||
|
browser_runner_.reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui_thread_.get()) {
|
||||||
|
// Blocks until the thread has stopped.
|
||||||
|
ui_thread_->Stop();
|
||||||
|
ui_thread_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shut down the content runner.
|
||||||
|
service_manager::MainShutdown(*sm_main_params_);
|
||||||
|
|
||||||
|
sm_main_params_.reset(nullptr);
|
||||||
|
sm_main_delegate_.reset(nullptr);
|
||||||
|
|
||||||
|
std::move(finalize_shutdown).Run();
|
||||||
|
if (IsCefRuntime())
|
||||||
|
CefMainDelegate::MainThreadShutdown();
|
||||||
|
|
||||||
|
main_delegate_.reset(nullptr);
|
||||||
|
runtime_type_ = RuntimeType::UNINITIALIZED;
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
// 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_MAIN_RUNNER_H_
|
||||||
|
#define CEF_LIBCEF_BROWSER_MAIN_RUNNER_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "libcef/common/main_delegate.h"
|
||||||
|
|
||||||
|
#include "base/callback_forward.h"
|
||||||
|
#include "base/macros.h"
|
||||||
|
#include "content/public/browser/browser_main_runner.h"
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
class WaitableEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace content {
|
||||||
|
class ContentMainDelegate;
|
||||||
|
class ContentServiceManagerMainDelegate;
|
||||||
|
struct MainFunctionParams;
|
||||||
|
} // namespace content
|
||||||
|
|
||||||
|
namespace service_manager {
|
||||||
|
struct MainParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CefUIThread;
|
||||||
|
|
||||||
|
// Manages the main process lifespan and related objects.
|
||||||
|
class CefMainRunner : public CefMainDelegate::Runner {
|
||||||
|
public:
|
||||||
|
CefMainRunner(bool multi_threaded_message_loop, bool external_message_pump);
|
||||||
|
~CefMainRunner();
|
||||||
|
|
||||||
|
// Called from CefContext::Initialize.
|
||||||
|
bool Initialize(CefSettings* settings,
|
||||||
|
CefRefPtr<CefApp> application,
|
||||||
|
const CefMainArgs& args,
|
||||||
|
void* windows_sandbox_info,
|
||||||
|
bool* initialized,
|
||||||
|
base::OnceClosure context_initialized);
|
||||||
|
|
||||||
|
// Called from CefContext::Shutdown.
|
||||||
|
void Shutdown(base::OnceClosure shutdown_on_ui_thread,
|
||||||
|
base::OnceClosure finalize_shutdown);
|
||||||
|
|
||||||
|
bool IsCefRuntime() const { return runtime_type_ == RuntimeType::CEF; }
|
||||||
|
|
||||||
|
// Called from CefExecuteProcess.
|
||||||
|
static int RunAsHelperProcess(const CefMainArgs& args,
|
||||||
|
CefRefPtr<CefApp> application,
|
||||||
|
void* windows_sandbox_info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Called from Initialize().
|
||||||
|
void CefRuntimeInitialize(CefSettings* settings, CefRefPtr<CefApp> app);
|
||||||
|
int ContentMainInitialize(const CefMainArgs& args,
|
||||||
|
void* windows_sandbox_info,
|
||||||
|
int* no_sandbox);
|
||||||
|
bool ContentMainRun(bool* initialized, base::OnceClosure context_initialized);
|
||||||
|
|
||||||
|
// CefMainDelegate::Runner methods:
|
||||||
|
void PreCreateMainMessageLoop() override;
|
||||||
|
int RunMainProcess(
|
||||||
|
const content::MainFunctionParams& main_function_params) override;
|
||||||
|
|
||||||
|
// Create the UI thread when running with multi-threaded message loop mode.
|
||||||
|
bool CreateUIThread(base::OnceClosure setup_callback);
|
||||||
|
|
||||||
|
// Called on the UI thread after the context is initialized.
|
||||||
|
void OnContextInitialized(base::OnceClosure context_initialized);
|
||||||
|
|
||||||
|
// Performs shutdown actions that need to occur on the UI thread before any
|
||||||
|
// threads are destroyed.
|
||||||
|
void FinishShutdownOnUIThread(base::OnceClosure shutdown_on_ui_thread,
|
||||||
|
base::WaitableEvent* uithread_shutdown_event);
|
||||||
|
|
||||||
|
// Destroys the runtime and related objects.
|
||||||
|
void FinalizeShutdown(base::OnceClosure finalize_shutdown);
|
||||||
|
|
||||||
|
const bool multi_threaded_message_loop_;
|
||||||
|
const bool external_message_pump_;
|
||||||
|
|
||||||
|
enum class RuntimeType {
|
||||||
|
UNINITIALIZED,
|
||||||
|
CEF,
|
||||||
|
};
|
||||||
|
RuntimeType runtime_type_ = RuntimeType::UNINITIALIZED;
|
||||||
|
|
||||||
|
std::unique_ptr<content::ContentMainDelegate> main_delegate_;
|
||||||
|
std::unique_ptr<content::ContentServiceManagerMainDelegate> sm_main_delegate_;
|
||||||
|
std::unique_ptr<service_manager::MainParams> sm_main_params_;
|
||||||
|
|
||||||
|
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
||||||
|
std::unique_ptr<CefUIThread> ui_thread_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CefMainRunner);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CEF_LIBCEF_BROWSER_MAIN_RUNNER_H_
|
|
@ -8,27 +8,24 @@
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libcef/browser/browser_message_loop.h"
|
#include "libcef/browser/chrome_browser_process_stub.h"
|
||||||
#include "libcef/browser/content_browser_client.h"
|
#include "libcef/browser/content_browser_client.h"
|
||||||
#include "libcef/browser/context.h"
|
|
||||||
#include "libcef/common/cef_switches.h"
|
#include "libcef/common/cef_switches.h"
|
||||||
#include "libcef/common/command_line_impl.h"
|
#include "libcef/common/command_line_impl.h"
|
||||||
#include "libcef/common/crash_reporting.h"
|
#include "libcef/common/crash_reporting.h"
|
||||||
#include "libcef/common/extensions/extensions_util.h"
|
#include "libcef/common/extensions/extensions_util.h"
|
||||||
|
#include "libcef/common/widevine_loader.h"
|
||||||
#include "libcef/renderer/content_renderer_client.h"
|
#include "libcef/renderer/content_renderer_client.h"
|
||||||
|
|
||||||
#include "base/at_exit.h"
|
|
||||||
#include "base/base_switches.h"
|
#include "base/base_switches.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
#include "base/path_service.h"
|
#include "base/path_service.h"
|
||||||
#include "base/run_loop.h"
|
|
||||||
#include "base/stl_util.h"
|
#include "base/stl_util.h"
|
||||||
#include "base/strings/string_number_conversions.h"
|
#include "base/strings/string_number_conversions.h"
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
#include "base/synchronization/waitable_event.h"
|
#include "base/synchronization/waitable_event.h"
|
||||||
#include "base/threading/thread.h"
|
|
||||||
#include "chrome/browser/browser_process.h"
|
#include "chrome/browser/browser_process.h"
|
||||||
#include "chrome/browser/media/router/media_router_feature.h"
|
#include "chrome/browser/media/router/media_router_feature.h"
|
||||||
#include "chrome/child/pdf_child_init.h"
|
#include "chrome/child/pdf_child_init.h"
|
||||||
|
@ -40,8 +37,6 @@
|
||||||
#include "components/content_settings/core/common/content_settings_pattern.h"
|
#include "components/content_settings/core/common/content_settings_pattern.h"
|
||||||
#include "components/viz/common/features.h"
|
#include "components/viz/common/features.h"
|
||||||
#include "content/browser/browser_process_sub_thread.h"
|
#include "content/browser/browser_process_sub_thread.h"
|
||||||
#include "content/browser/scheduler/browser_task_executor.h"
|
|
||||||
#include "content/public/browser/browser_main_runner.h"
|
|
||||||
#include "content/public/browser/render_process_host.h"
|
#include "content/public/browser/render_process_host.h"
|
||||||
#include "content/public/common/content_features.h"
|
#include "content/public/common/content_features.h"
|
||||||
#include "content/public/common/content_switches.h"
|
#include "content/public/common/content_switches.h"
|
||||||
|
@ -67,7 +62,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
#include <Objbase.h>
|
|
||||||
#include "base/win/registry.h"
|
#include "base/win/registry.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -245,10 +239,9 @@ bool GetDefaultUserDataDirectory(base::FilePath* result) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
base::FilePath GetUserDataPath() {
|
base::FilePath GetUserDataPath(CefSettings* settings) {
|
||||||
const CefSettings& settings = CefContext::Get()->settings();
|
if (settings->user_data_path.length > 0)
|
||||||
if (settings.user_data_path.length > 0)
|
return base::FilePath(CefString(&settings->user_data_path));
|
||||||
return base::FilePath(CefString(&settings.user_data_path));
|
|
||||||
|
|
||||||
base::FilePath result;
|
base::FilePath result;
|
||||||
if (GetDefaultUserDataDirectory(&result))
|
if (GetDefaultUserDataDirectory(&result))
|
||||||
|
@ -328,117 +321,10 @@ void OverrideAssetPath() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Used to run the UI on a separate thread.
|
CefMainDelegate::CefMainDelegate(Runner* runner,
|
||||||
class CefUIThread : public base::PlatformThread::Delegate {
|
CefSettings* settings,
|
||||||
public:
|
CefRefPtr<CefApp> application)
|
||||||
explicit CefUIThread(base::OnceClosure setup_callback)
|
: runner_(runner), settings_(settings), content_client_(application) {
|
||||||
: setup_callback_(std::move(setup_callback)) {}
|
|
||||||
~CefUIThread() override { Stop(); }
|
|
||||||
|
|
||||||
void Start() {
|
|
||||||
base::AutoLock lock(thread_lock_);
|
|
||||||
bool success = base::PlatformThread::CreateWithPriority(
|
|
||||||
0, this, &thread_, base::ThreadPriority::NORMAL);
|
|
||||||
if (!success) {
|
|
||||||
LOG(FATAL) << "failed to UI create thread";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stop() {
|
|
||||||
base::AutoLock lock(thread_lock_);
|
|
||||||
|
|
||||||
if (!stopping_) {
|
|
||||||
stopping_ = true;
|
|
||||||
base::PostTask(
|
|
||||||
FROM_HERE, {content::BrowserThread::UI},
|
|
||||||
base::BindOnce(&CefUIThread::ThreadQuitHelper, Unretained(this)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(
|
|
||||||
const content::MainFunctionParams& main_function_params) {
|
|
||||||
// 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(main_function_params);
|
|
||||||
CHECK_EQ(exit_code, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void ThreadMain() override {
|
|
||||||
base::PlatformThread::SetName("CefUIThread");
|
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
// Initializes the COM library on the current thread.
|
|
||||||
CoInitialize(nullptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
start_event_.Signal();
|
|
||||||
|
|
||||||
std::move(setup_callback_).Run();
|
|
||||||
|
|
||||||
base::RunLoop run_loop;
|
|
||||||
run_loop_ = &run_loop;
|
|
||||||
run_loop.Run();
|
|
||||||
|
|
||||||
browser_runner_->Shutdown();
|
|
||||||
browser_runner_.reset(nullptr);
|
|
||||||
|
|
||||||
content::BrowserTaskExecutor::Shutdown();
|
|
||||||
|
|
||||||
// Run exit callbacks on the UI thread to avoid sequence check failures.
|
|
||||||
base::AtExitManager::ProcessCallbacksNow();
|
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
// Closes the COM library on the current thread. CoInitialize must
|
|
||||||
// be balanced by a corresponding call to CoUninitialize.
|
|
||||||
CoUninitialize();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
run_loop_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThreadQuitHelper() {
|
|
||||||
DCHECK(run_loop_);
|
|
||||||
run_loop_->QuitWhenIdle();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
|
||||||
base::OnceClosure setup_callback_;
|
|
||||||
|
|
||||||
bool stopping_ = false;
|
|
||||||
|
|
||||||
// The thread's handle.
|
|
||||||
base::PlatformThreadHandle thread_;
|
|
||||||
mutable base::Lock thread_lock_; // Protects |thread_|.
|
|
||||||
|
|
||||||
base::RunLoop* run_loop_ = nullptr;
|
|
||||||
|
|
||||||
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_;
|
|
||||||
};
|
|
||||||
|
|
||||||
CefMainDelegate::CefMainDelegate(CefRefPtr<CefApp> application)
|
|
||||||
: content_client_(application) {
|
|
||||||
// Necessary so that exported functions from base_impl.cc will be included
|
// Necessary so that exported functions from base_impl.cc will be included
|
||||||
// in the binary.
|
// in the binary.
|
||||||
extern void base_impl_stub();
|
extern void base_impl_stub();
|
||||||
|
@ -452,7 +338,7 @@ CefMainDelegate::CefMainDelegate(CefRefPtr<CefApp> application)
|
||||||
CefMainDelegate::~CefMainDelegate() {}
|
CefMainDelegate::~CefMainDelegate() {}
|
||||||
|
|
||||||
void CefMainDelegate::PreCreateMainMessageLoop() {
|
void CefMainDelegate::PreCreateMainMessageLoop() {
|
||||||
InitMessagePumpFactoryForUI();
|
runner_->PreCreateMainMessageLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
|
@ -468,9 +354,7 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
|
|
||||||
if (process_type.empty()) {
|
if (process_type.empty()) {
|
||||||
// In the browser process. Populate the global command-line object.
|
// In the browser process. Populate the global command-line object.
|
||||||
const CefSettings& settings = CefContext::Get()->settings();
|
if (settings_->command_line_args_disabled) {
|
||||||
|
|
||||||
if (settings.command_line_args_disabled) {
|
|
||||||
// Remove any existing command-line arguments.
|
// Remove any existing command-line arguments.
|
||||||
base::CommandLine::StringVector argv;
|
base::CommandLine::StringVector argv;
|
||||||
argv.push_back(command_line->GetProgram().value());
|
argv.push_back(command_line->GetProgram().value());
|
||||||
|
@ -480,11 +364,11 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
const_cast<base::CommandLine::SwitchMap*>(&map)->clear();
|
const_cast<base::CommandLine::SwitchMap*>(&map)->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool no_sandbox = settings.no_sandbox ? true : false;
|
bool no_sandbox = settings_->no_sandbox ? true : false;
|
||||||
|
|
||||||
if (settings.browser_subprocess_path.length > 0) {
|
if (settings_->browser_subprocess_path.length > 0) {
|
||||||
base::FilePath file_path =
|
base::FilePath file_path =
|
||||||
base::FilePath(CefString(&settings.browser_subprocess_path));
|
base::FilePath(CefString(&settings_->browser_subprocess_path));
|
||||||
if (!file_path.empty()) {
|
if (!file_path.empty()) {
|
||||||
command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
|
command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
|
||||||
file_path);
|
file_path);
|
||||||
|
@ -498,16 +382,16 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
if (settings.framework_dir_path.length > 0) {
|
if (settings_->framework_dir_path.length > 0) {
|
||||||
base::FilePath file_path =
|
base::FilePath file_path =
|
||||||
base::FilePath(CefString(&settings.framework_dir_path));
|
base::FilePath(CefString(&settings_->framework_dir_path));
|
||||||
if (!file_path.empty())
|
if (!file_path.empty())
|
||||||
command_line->AppendSwitchPath(switches::kFrameworkDirPath, file_path);
|
command_line->AppendSwitchPath(switches::kFrameworkDirPath, file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.main_bundle_path.length > 0) {
|
if (settings_->main_bundle_path.length > 0) {
|
||||||
base::FilePath file_path =
|
base::FilePath file_path =
|
||||||
base::FilePath(CefString(&settings.main_bundle_path));
|
base::FilePath(CefString(&settings_->main_bundle_path));
|
||||||
if (!file_path.empty())
|
if (!file_path.empty())
|
||||||
command_line->AppendSwitchPath(switches::kMainBundlePath, file_path);
|
command_line->AppendSwitchPath(switches::kMainBundlePath, file_path);
|
||||||
}
|
}
|
||||||
|
@ -516,25 +400,25 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
if (no_sandbox)
|
if (no_sandbox)
|
||||||
command_line->AppendSwitch(service_manager::switches::kNoSandbox);
|
command_line->AppendSwitch(service_manager::switches::kNoSandbox);
|
||||||
|
|
||||||
if (settings.user_agent.length > 0) {
|
if (settings_->user_agent.length > 0) {
|
||||||
command_line->AppendSwitchASCII(switches::kUserAgent,
|
command_line->AppendSwitchASCII(switches::kUserAgent,
|
||||||
CefString(&settings.user_agent));
|
CefString(&settings_->user_agent));
|
||||||
} else if (settings.product_version.length > 0) {
|
} else if (settings_->product_version.length > 0) {
|
||||||
command_line->AppendSwitchASCII(switches::kProductVersion,
|
command_line->AppendSwitchASCII(switches::kProductVersion,
|
||||||
CefString(&settings.product_version));
|
CefString(&settings_->product_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.locale.length > 0) {
|
if (settings_->locale.length > 0) {
|
||||||
command_line->AppendSwitchASCII(switches::kLang,
|
command_line->AppendSwitchASCII(switches::kLang,
|
||||||
CefString(&settings.locale));
|
CefString(&settings_->locale));
|
||||||
} else if (!command_line->HasSwitch(switches::kLang)) {
|
} else if (!command_line->HasSwitch(switches::kLang)) {
|
||||||
command_line->AppendSwitchASCII(switches::kLang, "en-US");
|
command_line->AppendSwitchASCII(switches::kLang, "en-US");
|
||||||
}
|
}
|
||||||
|
|
||||||
base::FilePath log_file;
|
base::FilePath log_file;
|
||||||
bool has_log_file_cmdline = false;
|
bool has_log_file_cmdline = false;
|
||||||
if (settings.log_file.length > 0)
|
if (settings_->log_file.length > 0)
|
||||||
log_file = base::FilePath(CefString(&settings.log_file));
|
log_file = base::FilePath(CefString(&settings_->log_file));
|
||||||
if (log_file.empty() && command_line->HasSwitch(switches::kLogFile)) {
|
if (log_file.empty() && command_line->HasSwitch(switches::kLogFile)) {
|
||||||
log_file = command_line->GetSwitchValuePath(switches::kLogFile);
|
log_file = command_line->GetSwitchValuePath(switches::kLogFile);
|
||||||
if (!log_file.empty())
|
if (!log_file.empty())
|
||||||
|
@ -546,9 +430,9 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
if (!has_log_file_cmdline)
|
if (!has_log_file_cmdline)
|
||||||
command_line->AppendSwitchPath(switches::kLogFile, log_file);
|
command_line->AppendSwitchPath(switches::kLogFile, log_file);
|
||||||
|
|
||||||
if (settings.log_severity != LOGSEVERITY_DEFAULT) {
|
if (settings_->log_severity != LOGSEVERITY_DEFAULT) {
|
||||||
std::string log_severity;
|
std::string log_severity;
|
||||||
switch (settings.log_severity) {
|
switch (settings_->log_severity) {
|
||||||
case LOGSEVERITY_VERBOSE:
|
case LOGSEVERITY_VERBOSE:
|
||||||
log_severity = switches::kLogSeverity_Verbose;
|
log_severity = switches::kLogSeverity_Verbose;
|
||||||
break;
|
break;
|
||||||
|
@ -574,42 +458,42 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
command_line->AppendSwitchASCII(switches::kLogSeverity, log_severity);
|
command_line->AppendSwitchASCII(switches::kLogSeverity, log_severity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.javascript_flags.length > 0) {
|
if (settings_->javascript_flags.length > 0) {
|
||||||
command_line->AppendSwitchASCII(switches::kJavaScriptFlags,
|
command_line->AppendSwitchASCII(switches::kJavaScriptFlags,
|
||||||
CefString(&settings.javascript_flags));
|
CefString(&settings_->javascript_flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.pack_loading_disabled) {
|
if (settings_->pack_loading_disabled) {
|
||||||
command_line->AppendSwitch(switches::kDisablePackLoading);
|
command_line->AppendSwitch(switches::kDisablePackLoading);
|
||||||
} else {
|
} else {
|
||||||
if (settings.resources_dir_path.length > 0) {
|
if (settings_->resources_dir_path.length > 0) {
|
||||||
base::FilePath file_path =
|
base::FilePath file_path =
|
||||||
base::FilePath(CefString(&settings.resources_dir_path));
|
base::FilePath(CefString(&settings_->resources_dir_path));
|
||||||
if (!file_path.empty()) {
|
if (!file_path.empty()) {
|
||||||
command_line->AppendSwitchPath(switches::kResourcesDirPath,
|
command_line->AppendSwitchPath(switches::kResourcesDirPath,
|
||||||
file_path);
|
file_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.locales_dir_path.length > 0) {
|
if (settings_->locales_dir_path.length > 0) {
|
||||||
base::FilePath file_path =
|
base::FilePath file_path =
|
||||||
base::FilePath(CefString(&settings.locales_dir_path));
|
base::FilePath(CefString(&settings_->locales_dir_path));
|
||||||
if (!file_path.empty())
|
if (!file_path.empty())
|
||||||
command_line->AppendSwitchPath(switches::kLocalesDirPath, file_path);
|
command_line->AppendSwitchPath(switches::kLocalesDirPath, file_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.remote_debugging_port >= 1024 &&
|
if (settings_->remote_debugging_port >= 1024 &&
|
||||||
settings.remote_debugging_port <= 65535) {
|
settings_->remote_debugging_port <= 65535) {
|
||||||
command_line->AppendSwitchASCII(
|
command_line->AppendSwitchASCII(
|
||||||
switches::kRemoteDebuggingPort,
|
switches::kRemoteDebuggingPort,
|
||||||
base::NumberToString(settings.remote_debugging_port));
|
base::NumberToString(settings_->remote_debugging_port));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.uncaught_exception_stack_size > 0) {
|
if (settings_->uncaught_exception_stack_size > 0) {
|
||||||
command_line->AppendSwitchASCII(
|
command_line->AppendSwitchASCII(
|
||||||
switches::kUncaughtExceptionStackSize,
|
switches::kUncaughtExceptionStackSize,
|
||||||
base::NumberToString(settings.uncaught_exception_stack_size));
|
base::NumberToString(settings_->uncaught_exception_stack_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> disable_features;
|
std::vector<std::string> disable_features;
|
||||||
|
@ -765,7 +649,7 @@ void CefMainDelegate::PreSandboxStartup() {
|
||||||
dir_default_download_safe);
|
dir_default_download_safe);
|
||||||
}
|
}
|
||||||
|
|
||||||
const base::FilePath& user_data_path = GetUserDataPath();
|
const base::FilePath& user_data_path = GetUserDataPath(settings_);
|
||||||
base::PathService::Override(chrome::DIR_USER_DATA, user_data_path);
|
base::PathService::Override(chrome::DIR_USER_DATA, user_data_path);
|
||||||
|
|
||||||
// Path used for crash dumps.
|
// Path used for crash dumps.
|
||||||
|
@ -800,40 +684,12 @@ int CefMainDelegate::RunProcess(
|
||||||
const std::string& process_type,
|
const std::string& process_type,
|
||||||
const content::MainFunctionParams& main_function_params) {
|
const content::MainFunctionParams& main_function_params) {
|
||||||
if (process_type.empty()) {
|
if (process_type.empty()) {
|
||||||
const CefSettings& settings = CefContext::Get()->settings();
|
return runner_->RunMainProcess(main_function_params);
|
||||||
if (!settings.multi_threaded_message_loop) {
|
|
||||||
// Use our own browser process runner.
|
|
||||||
browser_runner_ = content::BrowserMainRunner::Create();
|
|
||||||
|
|
||||||
// Initialize browser process state. Results in a call to
|
|
||||||
// CefBrowserMain::PreMainMessageLoopStart() which creates the UI message
|
|
||||||
// loop.
|
|
||||||
int exit_code = browser_runner_->Initialize(main_function_params);
|
|
||||||
if (exit_code >= 0)
|
|
||||||
return exit_code;
|
|
||||||
} else {
|
|
||||||
// Running on the separate UI thread.
|
|
||||||
DCHECK(ui_thread_);
|
|
||||||
ui_thread_->InitializeBrowserRunner(main_function_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CefMainDelegate::CreateUIThread(base::OnceClosure setup_callback) {
|
|
||||||
DCHECK(!ui_thread_);
|
|
||||||
|
|
||||||
ui_thread_.reset(new CefUIThread(std::move(setup_callback)));
|
|
||||||
ui_thread_->Start();
|
|
||||||
ui_thread_->WaitUntilThreadStarted();
|
|
||||||
|
|
||||||
InitMessagePumpFactoryForUI();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CefMainDelegate::ProcessExiting(const std::string& process_type) {
|
void CefMainDelegate::ProcessExiting(const std::string& process_type) {
|
||||||
ui::ResourceBundle::CleanupSharedInstance();
|
ui::ResourceBundle::CleanupSharedInstance();
|
||||||
}
|
}
|
||||||
|
@ -863,17 +719,38 @@ content::ContentUtilityClient* CefMainDelegate::CreateContentUtilityClient() {
|
||||||
return utility_client_.get();
|
return utility_client_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CefMainDelegate::ShutdownBrowser() {
|
// static
|
||||||
if (browser_runner_.get()) {
|
void CefMainDelegate::CefInitialize() {
|
||||||
browser_runner_->Shutdown();
|
g_browser_process = new ChromeBrowserProcessStub();
|
||||||
browser_runner_.reset(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui_thread_.get()) {
|
// static
|
||||||
// Blocks until the thread has stopped.
|
void CefMainDelegate::MainThreadInitialize() {
|
||||||
ui_thread_->Stop();
|
static_cast<ChromeBrowserProcessStub*>(g_browser_process)->Initialize();
|
||||||
ui_thread_.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void CefMainDelegate::UIThreadInitialize() {
|
||||||
|
#if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
|
||||||
|
CefWidevineLoader::GetInstance()->OnContextInitialized();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static_cast<ChromeBrowserProcessStub*>(g_browser_process)
|
||||||
|
->OnContextInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void CefMainDelegate::UIThreadShutdown() {
|
||||||
|
static_cast<ChromeBrowserProcessStub*>(g_browser_process)
|
||||||
|
->CleanupOnUIThread();
|
||||||
|
|
||||||
|
ui::ResourceBundle::GetSharedInstance().CleanupOnUIThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void CefMainDelegate::MainThreadShutdown() {
|
||||||
|
delete g_browser_process;
|
||||||
|
g_browser_process = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CefMainDelegate::InitializeResourceBundle() {
|
void CefMainDelegate::InitializeResourceBundle() {
|
||||||
|
|
|
@ -16,22 +16,30 @@
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
class CommandLine;
|
class CommandLine;
|
||||||
class MessageLoop;
|
|
||||||
class Thread;
|
|
||||||
} // namespace base
|
|
||||||
|
|
||||||
namespace content {
|
|
||||||
class BrowserMainRunner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CefContentBrowserClient;
|
class CefContentBrowserClient;
|
||||||
class CefContentRendererClient;
|
class CefContentRendererClient;
|
||||||
class CefUIThread;
|
|
||||||
class ChromeContentUtilityClient;
|
class ChromeContentUtilityClient;
|
||||||
|
|
||||||
|
// Manages state specific to the CEF runtime.
|
||||||
class CefMainDelegate : public content::ContentMainDelegate {
|
class CefMainDelegate : public content::ContentMainDelegate {
|
||||||
public:
|
public:
|
||||||
explicit CefMainDelegate(CefRefPtr<CefApp> application);
|
class Runner {
|
||||||
|
public:
|
||||||
|
virtual void PreCreateMainMessageLoop() = 0;
|
||||||
|
virtual int RunMainProcess(
|
||||||
|
const content::MainFunctionParams& main_function_params) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~Runner() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// |runner| and |settings| will be non-nullptr for the main process only,
|
||||||
|
// and will outlive this object.
|
||||||
|
CefMainDelegate(Runner* runner,
|
||||||
|
CefSettings* settings,
|
||||||
|
CefRefPtr<CefApp> application);
|
||||||
~CefMainDelegate() override;
|
~CefMainDelegate() override;
|
||||||
|
|
||||||
void PreCreateMainMessageLoop() override;
|
void PreCreateMainMessageLoop() override;
|
||||||
|
@ -49,19 +57,22 @@ class CefMainDelegate : public content::ContentMainDelegate {
|
||||||
content::ContentRendererClient* CreateContentRendererClient() override;
|
content::ContentRendererClient* CreateContentRendererClient() override;
|
||||||
content::ContentUtilityClient* CreateContentUtilityClient() override;
|
content::ContentUtilityClient* CreateContentUtilityClient() override;
|
||||||
|
|
||||||
bool CreateUIThread(base::OnceClosure setup_callback);
|
|
||||||
|
|
||||||
// Shut down the browser runner.
|
|
||||||
void ShutdownBrowser();
|
|
||||||
|
|
||||||
CefContentBrowserClient* browser_client() { return browser_client_.get(); }
|
CefContentBrowserClient* browser_client() { return browser_client_.get(); }
|
||||||
CefContentClient* content_client() { return &content_client_; }
|
CefContentClient* content_client() { return &content_client_; }
|
||||||
|
|
||||||
|
// Called from MainRunner at various initialization/shutdown stages to create
|
||||||
|
// and clean up global state.
|
||||||
|
static void CefInitialize();
|
||||||
|
static void MainThreadInitialize();
|
||||||
|
static void UIThreadInitialize();
|
||||||
|
static void UIThreadShutdown();
|
||||||
|
static void MainThreadShutdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeResourceBundle();
|
void InitializeResourceBundle();
|
||||||
|
|
||||||
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
Runner* const runner_;
|
||||||
std::unique_ptr<CefUIThread> ui_thread_;
|
CefSettings* const settings_;
|
||||||
|
|
||||||
std::unique_ptr<CefContentBrowserClient> browser_client_;
|
std::unique_ptr<CefContentBrowserClient> browser_client_;
|
||||||
std::unique_ptr<CefContentRendererClient> renderer_client_;
|
std::unique_ptr<CefContentRendererClient> renderer_client_;
|
||||||
|
|
Loading…
Reference in New Issue