Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1430)

Unified Diff: content/browser/utility_process_host_impl.cc

Issue 18119009: Make utility process run in-process when running in single-process mode. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: add comment Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/utility_process_host_impl.cc
===================================================================
--- content/browser/utility_process_host_impl.cc (revision 209067)
+++ content/browser/utility_process_host_impl.cc (working copy)
@@ -7,15 +7,23 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
#include "content/browser/browser_child_process_host_impl.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/child/child_process.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/utility_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/utility_process_host_client.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/process_type.h"
+#include "content/utility/utility_thread_impl.h"
#include "ipc/ipc_switches.h"
#include "ui/base/ui_base_switches.h"
#include "webkit/plugins/plugin_switches.h"
@@ -45,6 +53,78 @@
};
#endif
+class UtilityMainThread : public base::Thread,
+ public base::MessageLoop::DestructionObserver {
+ public:
+ UtilityMainThread(const std::string& channel_id, IPC::Listener* listener)
+ : Thread("Chrome_InProcUtilityThread"),
+ channel_id_(channel_id),
+ listener_(listener),
+ done_event_(false, false),
+ quit_(false) {
+ channel_.reset(new IPC::Channel(
+ channel_id_, IPC::Channel::MODE_SERVER, listener_));
+ CHECK(channel_->Connect());
+ }
+
+ virtual ~UtilityMainThread() {
+ Stop();
+ }
+
+ void WaitForThreadToFlush() {
+ {
+ base::AutoLock auto_lock(quit_lock_);
+ if (quit_)
+ return;
+
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&UtilityMainThread::Flush, base::Unretained(this)));
+ }
+ done_event_.Wait();
+ }
+
+ IPC::Channel* channel() const { return channel_.get(); }
+
+ private:
+ // base::Thread implementation:
+ virtual void Init() OVERRIDE {
+ child_process_.reset(new ChildProcess());
+ child_process_->set_main_thread(new UtilityThreadImpl(channel_id_));
+ base::MessageLoop::current()->AddDestructionObserver(this);
+ }
+
+ virtual void CleanUp() OVERRIDE {
+ child_process_.reset();
+
+ // See comment in RendererMainThread.
+ SetThreadWasQuitProperly(true);
+ }
+
+ // base::MessageLoop::DestructionObserver implementation:
+ virtual void WillDestroyCurrentMessageLoop() OVERRIDE {
+ base::AutoLock auto_lock(quit_lock_);
+ quit_ = true;
+ done_event_.Signal();
+ }
+
+ void Flush() {
+ base::RunLoop().RunUntilIdle();
+ done_event_.Signal();
+ }
+
+ std::string channel_id_;
+ scoped_ptr<IPC::Channel> channel_;
+ IPC::Listener* listener_;
+ scoped_ptr<ChildProcess> child_process_;
+ base::WaitableEvent done_event_;
+
+ base::Lock quit_lock_; // Synchronizes access to quit_.
+ bool quit_; // Set to true when the thread destruction observer fires.
+
+ DISALLOW_COPY_AND_ASSIGN(UtilityMainThread);
+};
+
UtilityProcessHost* UtilityProcessHost::Create(
UtilityProcessHostClient* client,
base::SequencedTaskRunner* client_task_runner) {
@@ -64,8 +144,8 @@
child_flags_(ChildProcessHost::CHILD_NORMAL),
#endif
use_linux_zygote_(false),
- started_(false) {
- process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY, this));
+ started_(false),
+ fake_process_data_(PROCESS_TYPE_UTILITY) {
}
UtilityProcessHostImpl::~UtilityProcessHostImpl() {
@@ -77,6 +157,9 @@
if (!StartProcess())
return false;
+ if (in_process_thread_.get())
+ return in_process_thread_->channel()->Send(message);
+
return process_->Send(message);
}
@@ -106,6 +189,9 @@
}
const ChildProcessData& UtilityProcessHostImpl::GetData() {
+ if (in_process_thread_.get())
+ return fake_process_data_;
+
return process_->GetData();
}
@@ -124,84 +210,101 @@
if (is_batch_mode_)
return true;
- // Name must be set or metrics_service will crash in any test which
- // launches a UtilityProcessHost.
- process_->SetName(ASCIIToUTF16("utility process"));
- std::string channel_id = process_->GetHost()->CreateChannel();
- if (channel_id.empty())
- return false;
+ if (RenderProcessHost::run_renderer_in_process()) {
+ // See comment in RenderProcessHostImpl::Init() for the background on why we
+ // support single process mode this way.
+ const std::string channel_id =
+ IPC::Channel::GenerateVerifiedChannelID(std::string());
+ in_process_thread_.reset(new UtilityMainThread(channel_id, this));
+ in_process_thread_->Start();
+ } else {
+ // Name must be set or metrics_service will crash in any test which
+ // launches a UtilityProcessHost.
+ process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY, this));
+ process_->SetName(ASCIIToUTF16("utility process"));
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- int child_flags = child_flags_;
+ std::string channel_id = process_->GetHost()->CreateChannel();
+ if (channel_id.empty())
+ return false;
+ const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ int child_flags = child_flags_;
+
#if defined(OS_POSIX)
- bool has_cmd_prefix = browser_command_line.HasSwitch(
- switches::kUtilityCmdPrefix);
+ bool has_cmd_prefix = browser_command_line.HasSwitch(
+ switches::kUtilityCmdPrefix);
- // When running under gdb, forking /proc/self/exe ends up forking the gdb
- // executable instead of Chromium. It is almost safe to assume that no
- // updates will happen while a developer is running with
- // |switches::kUtilityCmdPrefix|. See ChildProcessHost::GetChildPath() for
- // a similar case with Valgrind.
- if (has_cmd_prefix)
- child_flags = ChildProcessHost::CHILD_NORMAL;
+ // When running under gdb, forking /proc/self/exe ends up forking the gdb
+ // executable instead of Chromium. It is almost safe to assume that no
+ // updates will happen while a developer is running with
+ // |switches::kUtilityCmdPrefix|. See ChildProcessHost::GetChildPath() for
+ // a similar case with Valgrind.
+ if (has_cmd_prefix)
+ child_flags = ChildProcessHost::CHILD_NORMAL;
#endif
- base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
- if (exe_path.empty()) {
- NOTREACHED() << "Unable to get utility process binary name.";
- return false;
- }
+ base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
+ if (exe_path.empty()) {
+ NOTREACHED() << "Unable to get utility process binary name.";
+ return false;
+ }
- CommandLine* cmd_line = new CommandLine(exe_path);
- cmd_line->AppendSwitchASCII(switches::kProcessType,
- switches::kUtilityProcess);
- cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
- std::string locale = GetContentClient()->browser()->GetApplicationLocale();
- cmd_line->AppendSwitchASCII(switches::kLang, locale);
+ CommandLine* cmd_line = new CommandLine(exe_path);
+ cmd_line->AppendSwitchASCII(switches::kProcessType,
+ switches::kUtilityProcess);
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
+ std::string locale = GetContentClient()->browser()->GetApplicationLocale();
+ cmd_line->AppendSwitchASCII(switches::kLang, locale);
- if (no_sandbox_ || browser_command_line.HasSwitch(switches::kNoSandbox))
- cmd_line->AppendSwitch(switches::kNoSandbox);
+ if (no_sandbox_ || browser_command_line.HasSwitch(switches::kNoSandbox))
+ cmd_line->AppendSwitch(switches::kNoSandbox);
#if defined(OS_MACOSX)
- if (browser_command_line.HasSwitch(switches::kEnableSandboxLogging))
- cmd_line->AppendSwitch(switches::kEnableSandboxLogging);
+ if (browser_command_line.HasSwitch(switches::kEnableSandboxLogging))
+ cmd_line->AppendSwitch(switches::kEnableSandboxLogging);
#endif
- if (browser_command_line.HasSwitch(switches::kDebugPluginLoading))
- cmd_line->AppendSwitch(switches::kDebugPluginLoading);
+ if (browser_command_line.HasSwitch(switches::kDebugPluginLoading))
+ cmd_line->AppendSwitch(switches::kDebugPluginLoading);
#if defined(OS_POSIX)
- // TODO(port): Sandbox this on Linux. Also, zygote this to work with
- // Linux updating.
- if (has_cmd_prefix) {
- // launch the utility child process with some prefix (usually "xterm -e gdb
- // --args").
- cmd_line->PrependWrapper(browser_command_line.GetSwitchValueNative(
- switches::kUtilityCmdPrefix));
- }
+ // TODO(port): Sandbox this on Linux. Also, zygote this to work with
+ // Linux updating.
+ if (has_cmd_prefix) {
+ // launch the utility child process with some prefix (usually "xterm -e gdb
+ // --args").
+ cmd_line->PrependWrapper(browser_command_line.GetSwitchValueNative(
+ switches::kUtilityCmdPrefix));
+ }
- cmd_line->AppendSwitchPath(switches::kUtilityProcessAllowedDir, exposed_dir_);
+ cmd_line->AppendSwitchPath(switches::kUtilityProcessAllowedDir, exposed_dir_);
#endif
- bool use_zygote = false;
+ bool use_zygote = false;
#if defined(OS_LINUX)
- use_zygote = !no_sandbox_ && use_linux_zygote_;
+ use_zygote = !no_sandbox_ && use_linux_zygote_;
#endif
- process_->Launch(
+ process_->Launch(
#if defined(OS_WIN)
- new UtilitySandboxedProcessLauncherDelegate(exposed_dir_),
+ new UtilitySandboxedProcessLauncherDelegate(exposed_dir_),
#elif defined(OS_POSIX)
- use_zygote,
- env_,
+ use_zygote,
+ env_,
#endif
- cmd_line);
+ cmd_line);
+ }
return true;
}
bool UtilityProcessHostImpl::OnMessageReceived(const IPC::Message& message) {
+ if (in_process_thread_.get()) {
+ // When running in single process mode, wait on the thread to flush its
+ // tasks after every message. This is important for unittests so that we
+ // cleanup.
+ in_process_thread_->WaitForThreadToFlush();
+ }
client_task_runner_->PostTask(
FROM_HERE,
base::Bind(base::IgnoreResult(

Powered by Google App Engine
This is Rietveld 408576698