mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add initial chrome runtime support (see issue #2969)
Running `cefsimple --enable-chrome-runtime` will create and run a Chrome browser window using the CEF app methods, and call CefApp::OnContextInitialized as expected. CEF task methods also work as expected in the main process. No browser-related methods or callbacks are currently supported for the Chrome window, and the application will exit when the last Chrome window closes. The Chrome runtime requires resources.pak, chrome_100_percent.pak and chrome_200_percent.pak files which were not previously built with CEF. It shares the existing locales pak files which have been updated to include additional Chrome-specific strings. On Linux, the Chrome runtime requires GTK so use_gtk=true must be specified via GN_DEFINES when building. This change also refactors the CEF runtime, which can be tested in the various supported modes by running: $ cefclient $ cefclient --multi-threaded-message-loop $ cefclient --external-message-pump
This commit is contained in:
@@ -7,7 +7,10 @@
|
||||
|
||||
#include "libcef/browser/browser_message_loop.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
#include "libcef/renderer/content_renderer_client.h"
|
||||
#include "libcef/common/cef_switches.h"
|
||||
#include "libcef/common/chrome/chrome_main_runner_delegate.h"
|
||||
#include "libcef/common/main_delegate.h"
|
||||
#include "libcef/features/chrome_cef.h"
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/base_switches.h"
|
||||
@@ -38,6 +41,27 @@
|
||||
|
||||
namespace {
|
||||
|
||||
enum class RuntimeType {
|
||||
UNINITIALIZED,
|
||||
CEF,
|
||||
CHROME,
|
||||
};
|
||||
RuntimeType g_runtime_type = RuntimeType::UNINITIALIZED;
|
||||
|
||||
std::unique_ptr<CefMainRunnerDelegate> MakeDelegate(
|
||||
RuntimeType type,
|
||||
CefMainRunnerHandler* runner,
|
||||
CefSettings* settings,
|
||||
CefRefPtr<CefApp> application) {
|
||||
if (type == RuntimeType::CEF) {
|
||||
g_runtime_type = RuntimeType::CEF;
|
||||
return std::make_unique<CefMainDelegate>(runner, settings, application);
|
||||
} else {
|
||||
g_runtime_type = RuntimeType::CHROME;
|
||||
return std::make_unique<ChromeMainRunnerDelegate>(runner);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||
|
||||
// Based on components/crash/core/app/run_as_crashpad_handler_win.cc
|
||||
@@ -91,8 +115,8 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line) {
|
||||
// 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(CefMainRunner* runner, base::OnceClosure setup_callback)
|
||||
: runner_(runner), setup_callback_(std::move(setup_callback)) {}
|
||||
~CefUIThread() override { Stop(); }
|
||||
|
||||
void Start() {
|
||||
@@ -109,8 +133,8 @@ class CefUIThread : public base::PlatformThread::Delegate {
|
||||
|
||||
if (!stopping_) {
|
||||
stopping_ = true;
|
||||
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefUIThread::ThreadQuitHelper,
|
||||
base::Unretained(this)));
|
||||
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.
|
||||
@@ -152,12 +176,10 @@ class CefUIThread : public base::PlatformThread::Delegate {
|
||||
|
||||
std::move(setup_callback_).Run();
|
||||
|
||||
base::RunLoop run_loop;
|
||||
run_loop_ = &run_loop;
|
||||
run_loop.Run();
|
||||
runner_->RunMessageLoop();
|
||||
|
||||
browser_runner_->Shutdown();
|
||||
browser_runner_.reset(nullptr);
|
||||
browser_runner_.reset();
|
||||
|
||||
content::BrowserTaskExecutor::Shutdown();
|
||||
|
||||
@@ -169,17 +191,12 @@ class CefUIThread : public base::PlatformThread::Delegate {
|
||||
// be balanced by a corresponding call to CoUninitialize.
|
||||
CoUninitialize();
|
||||
#endif
|
||||
|
||||
run_loop_ = nullptr;
|
||||
}
|
||||
|
||||
void ThreadQuitHelper() {
|
||||
DCHECK(run_loop_);
|
||||
run_loop_->QuitWhenIdle();
|
||||
}
|
||||
CefMainRunner* const runner_;
|
||||
base::OnceClosure setup_callback_;
|
||||
|
||||
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
||||
base::OnceClosure setup_callback_;
|
||||
|
||||
bool stopping_ = false;
|
||||
|
||||
@@ -187,8 +204,6 @@ class CefUIThread : public base::PlatformThread::Delegate {
|
||||
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
|
||||
@@ -209,7 +224,10 @@ bool CefMainRunner::Initialize(CefSettings* settings,
|
||||
void* windows_sandbox_info,
|
||||
bool* initialized,
|
||||
base::OnceClosure context_initialized) {
|
||||
CefRuntimeInitialize(settings, application);
|
||||
DCHECK(!main_delegate_);
|
||||
main_delegate_ = MakeDelegate(
|
||||
settings->chrome_runtime ? RuntimeType::CHROME : RuntimeType::CEF, this,
|
||||
settings, application);
|
||||
|
||||
const int exit_code =
|
||||
ContentMainInitialize(args, windows_sandbox_info, &settings->no_sandbox);
|
||||
@@ -254,6 +272,25 @@ void CefMainRunner::Shutdown(base::OnceClosure shutdown_on_ui_thread,
|
||||
}
|
||||
}
|
||||
|
||||
void CefMainRunner::RunMessageLoop() {
|
||||
base::RunLoop run_loop;
|
||||
|
||||
DCHECK(quit_when_idle_callback_.is_null());
|
||||
quit_when_idle_callback_ = run_loop.QuitWhenIdleClosure();
|
||||
|
||||
main_delegate_->BeforeMainMessageLoopRun(&run_loop);
|
||||
|
||||
// Blocks until QuitMessageLoop() is called.
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
void CefMainRunner::QuitMessageLoop() {
|
||||
if (!quit_when_idle_callback_.is_null()) {
|
||||
main_delegate_->BeforeMainMessageLoopQuit();
|
||||
std::move(quit_when_idle_callback_).Run();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
|
||||
CefRefPtr<CefApp> application,
|
||||
@@ -276,16 +313,25 @@ int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
|
||||
if (process_type.empty())
|
||||
return -1;
|
||||
|
||||
auto runtime_type = command_line.HasSwitch(switches::kEnableChromeRuntime)
|
||||
? RuntimeType::CHROME
|
||||
: RuntimeType::CEF;
|
||||
auto main_delegate = MakeDelegate(runtime_type, /*runner=*/nullptr,
|
||||
/*settings=*/nullptr, application);
|
||||
main_delegate->BeforeExecuteProcess(args);
|
||||
|
||||
int result;
|
||||
|
||||
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||
if (process_type == crash_reporter::switches::kCrashpadHandler)
|
||||
return RunAsCrashpadHandler(command_line);
|
||||
if (process_type == crash_reporter::switches::kCrashpadHandler) {
|
||||
result = RunAsCrashpadHandler(command_line);
|
||||
main_delegate->AfterExecuteProcess();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<content::ContentMainDelegate> main_delegate;
|
||||
main_delegate.reset(new CefMainDelegate(/*context=*/nullptr,
|
||||
/*settings=*/nullptr, application));
|
||||
|
||||
// Execute the secondary process.
|
||||
// Execute the secondary process.
|
||||
content::ContentMainParams params(main_delegate->GetContentMainDelegate());
|
||||
#if defined(OS_WIN)
|
||||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||
if (windows_sandbox_info == nullptr) {
|
||||
@@ -293,38 +339,27 @@ int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
|
||||
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
|
||||
}
|
||||
result = content::ContentMain(params);
|
||||
|
||||
void CefMainRunner::CefRuntimeInitialize(CefSettings* settings,
|
||||
CefRefPtr<CefApp> app) {
|
||||
DCHECK_EQ(RuntimeType::UNINITIALIZED, runtime_type_);
|
||||
DCHECK(!main_delegate_);
|
||||
main_delegate->AfterExecuteProcess();
|
||||
|
||||
runtime_type_ = RuntimeType::CEF;
|
||||
CefMainDelegate::CefInitialize();
|
||||
main_delegate_.reset(new CefMainDelegate(this, settings, app));
|
||||
return result;
|
||||
}
|
||||
|
||||
int CefMainRunner::ContentMainInitialize(const CefMainArgs& args,
|
||||
void* windows_sandbox_info,
|
||||
int* no_sandbox) {
|
||||
DCHECK(main_delegate_);
|
||||
main_delegate_->BeforeMainThreadInitialize(args);
|
||||
|
||||
// Initialize the content runner.
|
||||
content::ContentMainParams params(main_delegate_.get());
|
||||
content::ContentMainParams params(main_delegate_->GetContentMainDelegate());
|
||||
#if defined(OS_WIN)
|
||||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||
if (windows_sandbox_info == nullptr) {
|
||||
@@ -355,8 +390,7 @@ int CefMainRunner::ContentMainInitialize(const CefMainArgs& args,
|
||||
|
||||
bool CefMainRunner::ContentMainRun(bool* initialized,
|
||||
base::OnceClosure context_initialized) {
|
||||
if (IsCefRuntime())
|
||||
CefMainDelegate::MainThreadInitialize();
|
||||
main_delegate_->BeforeMainThreadRun();
|
||||
|
||||
if (multi_threaded_message_loop_) {
|
||||
base::WaitableEvent uithread_startup_event(
|
||||
@@ -424,7 +458,7 @@ int CefMainRunner::RunMainProcess(
|
||||
bool CefMainRunner::CreateUIThread(base::OnceClosure setup_callback) {
|
||||
DCHECK(!ui_thread_);
|
||||
|
||||
ui_thread_.reset(new CefUIThread(std::move(setup_callback)));
|
||||
ui_thread_.reset(new CefUIThread(this, std::move(setup_callback)));
|
||||
ui_thread_->Start();
|
||||
ui_thread_->WaitUntilThreadStarted();
|
||||
|
||||
@@ -437,8 +471,8 @@ bool CefMainRunner::CreateUIThread(base::OnceClosure setup_callback) {
|
||||
void CefMainRunner::OnContextInitialized(
|
||||
base::OnceClosure context_initialized) {
|
||||
CEF_REQUIRE_UIT();
|
||||
if (IsCefRuntime())
|
||||
CefMainDelegate::UIThreadInitialize();
|
||||
|
||||
main_delegate_->AfterUIThreadInitialize();
|
||||
std::move(context_initialized).Run();
|
||||
}
|
||||
|
||||
@@ -450,22 +484,18 @@ void CefMainRunner::FinishShutdownOnUIThread(
|
||||
sm_main_delegate_->ShutdownOnUIThread();
|
||||
|
||||
std::move(shutdown_on_ui_thread).Run();
|
||||
if (IsCefRuntime())
|
||||
CefMainDelegate::UIThreadShutdown();
|
||||
main_delegate_->AfterUIThreadShutdown();
|
||||
|
||||
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();
|
||||
}
|
||||
main_delegate_->BeforeMainThreadShutdown();
|
||||
|
||||
if (browser_runner_.get()) {
|
||||
browser_runner_->Shutdown();
|
||||
browser_runner_.reset(nullptr);
|
||||
browser_runner_.reset();
|
||||
}
|
||||
|
||||
if (ui_thread_.get()) {
|
||||
@@ -477,13 +507,25 @@ void CefMainRunner::FinalizeShutdown(base::OnceClosure finalize_shutdown) {
|
||||
// Shut down the content runner.
|
||||
service_manager::MainShutdown(*sm_main_params_);
|
||||
|
||||
sm_main_params_.reset(nullptr);
|
||||
sm_main_delegate_.reset(nullptr);
|
||||
sm_main_params_.reset();
|
||||
sm_main_delegate_.reset();
|
||||
|
||||
std::move(finalize_shutdown).Run();
|
||||
if (IsCefRuntime())
|
||||
CefMainDelegate::MainThreadShutdown();
|
||||
main_delegate_->AfterMainThreadShutdown();
|
||||
|
||||
main_delegate_.reset(nullptr);
|
||||
runtime_type_ = RuntimeType::UNINITIALIZED;
|
||||
main_delegate_.reset();
|
||||
g_runtime_type = RuntimeType::UNINITIALIZED;
|
||||
}
|
||||
|
||||
// From libcef/features/chrome_cef.h:
|
||||
namespace cef {
|
||||
|
||||
bool IsCefRuntimeEnabled() {
|
||||
return g_runtime_type == RuntimeType::CEF;
|
||||
}
|
||||
|
||||
bool IsChromeRuntimeEnabled() {
|
||||
return g_runtime_type == RuntimeType::CHROME;
|
||||
}
|
||||
|
||||
} // namespace cef
|
||||
|
Reference in New Issue
Block a user