Fix crashes when running with multi-threaded message loop (issue #2565)
This commit is contained in:
parent
7f08159461
commit
27fb4694ed
|
@ -24,6 +24,7 @@
|
|||
#include "base/synchronization/waitable_event.h"
|
||||
#include "components/network_session_configurator/common/network_switches.h"
|
||||
#include "content/app/content_service_manager_main_delegate.h"
|
||||
#include "content/browser/startup_helper.h"
|
||||
#include "content/public/browser/notification_service.h"
|
||||
#include "content/public/browser/notification_types.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
|
@ -123,7 +124,7 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line) {
|
|||
argv.insert(argv.begin(), command_line.GetProgram().value());
|
||||
#endif
|
||||
|
||||
std::unique_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
|
||||
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) {
|
||||
|
@ -409,11 +410,38 @@ bool CefContext::Initialize(const CefMainArgs& args,
|
|||
|
||||
static_cast<ChromeBrowserProcessStub*>(g_browser_process)->Initialize();
|
||||
|
||||
// Run the process. Results in a call to CefMainDelegate::RunProcess() which
|
||||
// will create the browser runner and message loop without blocking.
|
||||
exit_code = service_manager::MainRun(*sm_main_params_);
|
||||
if (settings.multi_threaded_message_loop) {
|
||||
base::WaitableEvent uithread_startup_event(
|
||||
base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||
base::WaitableEvent::InitialState::NOT_SIGNALED);
|
||||
|
||||
initialized_ = true;
|
||||
// This is required because creating a base::Thread as starting it will
|
||||
// check some feature flags this will cause a CHECK failure later when this
|
||||
// gets called by some call down the line of service_manager::MainRun.
|
||||
content::SetUpFieldTrialsAndFeatureList();
|
||||
|
||||
if (!main_delegate_->CreateUIThread()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
// Can't use CEF_POST_TASK here yet, because the TaskRunner is not yet set.
|
||||
main_delegate_->ui_thread()->task_runner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(
|
||||
[](CefContext* context, base::WaitableEvent* event) {
|
||||
service_manager::MainRun(*context->sm_main_params_);
|
||||
event->Signal();
|
||||
},
|
||||
base::Unretained(this), base::Unretained(&uithread_startup_event)));
|
||||
|
||||
// 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();
|
||||
|
|
|
@ -259,21 +259,24 @@ bool IsScaleFactorSupported(ui::ScaleFactor scale_factor) {
|
|||
// Used to run the UI on a separate thread.
|
||||
class CefUIThread : public base::Thread {
|
||||
public:
|
||||
CefUIThread(const content::MainFunctionParams& main_function_params)
|
||||
: base::Thread("CefUIThread"),
|
||||
main_function_params_(main_function_params) {}
|
||||
CefUIThread() : base::Thread("CefUIThread") {}
|
||||
|
||||
void Init() override {
|
||||
#if defined(OS_WIN)
|
||||
// Initializes the COM library on the current thread.
|
||||
CoInitialize(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeBrowserRunner(
|
||||
const content::MainFunctionParams& main_function_params) {
|
||||
DCHECK(task_runner()->BelongsToCurrentThread());
|
||||
|
||||
// Use our own browser process runner.
|
||||
browser_runner_.reset(content::BrowserMainRunner::Create());
|
||||
|
||||
// Initialize browser process state. Uses the current thread's mesage loop.
|
||||
int exit_code = browser_runner_->Initialize(main_function_params_);
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -298,7 +301,6 @@ class CefUIThread : public base::Thread {
|
|||
}
|
||||
|
||||
protected:
|
||||
content::MainFunctionParams main_function_params_;
|
||||
std::unique_ptr<content::BrowserMainRunner> browser_runner_;
|
||||
};
|
||||
|
||||
|
@ -315,8 +317,10 @@ CefMainDelegate::CefMainDelegate(CefRefPtr<CefApp> application)
|
|||
CefMainDelegate::~CefMainDelegate() {}
|
||||
|
||||
void CefMainDelegate::PreCreateMainMessageLoop() {
|
||||
// Create the main message loop.
|
||||
message_loop_.reset(new CefBrowserMessageLoop());
|
||||
if (!message_loop_) {
|
||||
// Create the main message loop.
|
||||
message_loop_.reset(new CefBrowserMessageLoop());
|
||||
}
|
||||
}
|
||||
|
||||
bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
|
@ -591,17 +595,10 @@ int CefMainDelegate::RunProcess(
|
|||
if (exit_code >= 0)
|
||||
return exit_code;
|
||||
} else {
|
||||
// Run the UI on a separate thread.
|
||||
std::unique_ptr<base::Thread> thread;
|
||||
thread.reset(new CefUIThread(main_function_params));
|
||||
base::Thread::Options options;
|
||||
options.message_loop_type = base::MessageLoop::TYPE_UI;
|
||||
if (!thread->StartWithOptions(options)) {
|
||||
NOTREACHED() << "failed to start UI thread";
|
||||
return 1;
|
||||
}
|
||||
thread->WaitUntilThreadStarted();
|
||||
ui_thread_.swap(thread);
|
||||
// Running on the separate UI thread.
|
||||
DCHECK(ui_thread_);
|
||||
static_cast<CefUIThread*>(ui_thread_.get())
|
||||
->InitializeBrowserRunner(main_function_params);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -610,6 +607,25 @@ int CefMainDelegate::RunProcess(
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool CefMainDelegate::CreateUIThread() {
|
||||
DCHECK(!ui_thread_);
|
||||
DCHECK(!message_loop_);
|
||||
|
||||
std::unique_ptr<base::Thread> thread;
|
||||
thread.reset(new CefUIThread());
|
||||
base::Thread::Options options;
|
||||
options.message_loop_type = base::MessageLoop::TYPE_UI;
|
||||
if (!thread->StartWithOptions(options)) {
|
||||
NOTREACHED() << "failed to start UI thread";
|
||||
return false;
|
||||
}
|
||||
thread->WaitUntilThreadStarted();
|
||||
ui_thread_.swap(thread);
|
||||
|
||||
message_loop_.reset(new CefBrowserMessageLoop());
|
||||
return true;
|
||||
}
|
||||
|
||||
void CefMainDelegate::ProcessExiting(const std::string& process_type) {
|
||||
ui::ResourceBundle::CleanupSharedInstance();
|
||||
}
|
||||
|
|
|
@ -48,11 +48,14 @@ class CefMainDelegate : public content::ContentMainDelegate {
|
|||
content::ContentRendererClient* CreateContentRendererClient() override;
|
||||
content::ContentUtilityClient* CreateContentUtilityClient() override;
|
||||
|
||||
bool CreateUIThread();
|
||||
|
||||
// Shut down the browser runner.
|
||||
void ShutdownBrowser();
|
||||
|
||||
CefContentBrowserClient* browser_client() { return browser_client_.get(); }
|
||||
CefContentClient* content_client() { return &content_client_; }
|
||||
base::Thread* ui_thread() { return ui_thread_.get(); }
|
||||
|
||||
private:
|
||||
void InitializeResourceBundle();
|
||||
|
|
Loading…
Reference in New Issue