summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-21 21:15:09 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-21 21:15:09 +0000
commitb7315211fa8a8468102ac3675f21c875a6c83d0b (patch)
tree02d499f93080e86990cae70d40732ebf5dfe6677
parentdf0dcd4a244db43f760872c3e607e642ccde2a25 (diff)
downloadchromium_src-b7315211fa8a8468102ac3675f21c875a6c83d0b.zip
chromium_src-b7315211fa8a8468102ac3675f21c875a6c83d0b.tar.gz
chromium_src-b7315211fa8a8468102ac3675f21c875a6c83d0b.tar.bz2
Merge 32750 - Launch all child processes asynchronously so as not to block the IO thread.
BUG=6844, 27935 Review URL: http://codereview.chromium.org/402097 TBR=jam@chromium.org Review URL: http://codereview.chromium.org/418046 git-svn-id: svn://svn.chromium.org/chrome/branches/249/src@32753 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/child_process_launcher.cc155
-rw-r--r--chrome/browser/child_process_launcher.h18
-rw-r--r--chrome/browser/nacl_process_host.cc198
-rw-r--r--chrome/browser/nacl_process_host.h33
-rw-r--r--chrome/browser/plugin_process_host.cc108
-rw-r--r--chrome/browser/plugin_process_host.h7
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc16
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc25
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc18
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h4
-rw-r--r--chrome/browser/task_manager_resource_providers.cc8
-rw-r--r--chrome/browser/utility_process_host.cc79
-rw-r--r--chrome/browser/utility_process_host.h2
-rw-r--r--chrome/browser/worker_host/worker_process_host.cc49
-rw-r--r--chrome/common/child_process_host.cc57
-rw-r--r--chrome/common/child_process_host.h39
-rw-r--r--chrome/worker/worker_uitest.cc3
17 files changed, 430 insertions, 389 deletions
diff --git a/chrome/browser/child_process_launcher.cc b/chrome/browser/child_process_launcher.cc
index a028492..b7933c6 100644
--- a/chrome/browser/child_process_launcher.cc
+++ b/chrome/browser/child_process_launcher.cc
@@ -14,7 +14,6 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/result_codes.h"
-#include "ipc/ipc_sync_channel.h"
#if defined(OS_WIN)
#include "chrome/browser/sandbox_policy.h"
@@ -25,6 +24,10 @@
#include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
#endif
+#if defined(OS_POSIX)
+#include "base/global_descriptors_posix.h"
+#endif
+
namespace {
class LauncherThread : public base::Thread {
@@ -41,9 +44,23 @@ static base::LazyInstance<LauncherThread> launcher(base::LINKER_INITIALIZED);
class ChildProcessLauncher::Context
: public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
public:
- Context() : starting_(true), zygote_(false) {}
+ Context()
+ : starting_(true)
+#if defined(OS_LINUX)
+ , zygote_(false)
+#endif
+ {
+ }
- void Launch(CommandLine* cmd_line, int ipcfd, Client* client) {
+ void Launch(
+#if defined(OS_WIN)
+ const FilePath& exposed_dir,
+#elif defined(OS_POSIX)
+ const base::environment_vector& environ,
+ int ipcfd,
+#endif
+ CommandLine* cmd_line,
+ Client* client) {
client_ = client;
CHECK(ChromeThread::GetCurrentThreadIdentifier(&client_thread_id_));
@@ -53,7 +70,14 @@ class ChildProcessLauncher::Context
launcher.Get().message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(
- this, &Context::LaunchInternal, ipcfd, cmd_line));
+ this,
+ &Context::LaunchInternal,
+#if defined(OS_WIN)
+ exposed_dir,
+#elif defined(POSIX)
+ ipcfd,
+#endif
+ cmd_line));
}
void ResetClient() {
@@ -71,19 +95,31 @@ class ChildProcessLauncher::Context
Terminate();
}
- void LaunchInternal(int ipcfd, CommandLine* cmd_line) {
+ void LaunchInternal(
+#if defined(OS_WIN)
+ const FilePath& exposed_dir,
+#elif defined(OS_POSIX)
+ int ipcfd,
+#endif
+ CommandLine* cmd_line) {
scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
base::ProcessHandle handle = base::kNullProcessHandle;
- bool zygote = false;
#if defined(OS_WIN)
- handle = sandbox::StartProcess(cmd_line);
+ handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir);
#elif defined(OS_POSIX)
#if defined(OS_LINUX)
- // On Linux, normally spawn processes with zygotes. We can't do this when
- // we're spawning child processes through an external program (i.e. there is
- // a command prefix) like GDB so fall through to the POSIX case then.
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ bool zygote = false;
+ // On Linux, normally spawn renderer processes with zygotes. We can't do
+ // this when we're spawning child processes through an external program
+ // (i.e. there is a command prefix) like GDB so fall through to the POSIX
+ // case then.
+ bool is_renderer = cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
+ switches::kRendererProcess;
+ bool is_plugin = cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
+ switches::kPluginProcess;
+ if (is_renderer &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRendererCmdPrefix)) {
zygote = true;
@@ -97,24 +133,40 @@ class ChildProcessLauncher::Context
}
handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping);
}
-#endif
- if (!zygote) {
+ if (!zygote)
+#endif
+ {
base::file_handle_mapping_vector fds_to_map;
- fds_to_map.push_back(std::make_pair(ipcfd, kPrimaryIPCChannel + 3));
+ fds_to_map.push_back(std::make_pair(
+ ipcfd,
+ kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
#if defined(OS_LINUX)
// On Linux, we need to add some extra file descriptors for crash handling
// and the sandbox.
- const int crash_signal_fd =
- Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket();
- if (crash_signal_fd >= 0) {
- fds_to_map.push_back(std::make_pair(crash_signal_fd,
- kCrashDumpSignal + 3));
+ if (is_renderer || is_plugin) {
+ int crash_signal_fd;
+ if (is_renderer) {
+ crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()->
+ GetDeathSignalSocket();
+ } else {
+ crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()->
+ GetDeathSignalSocket();
+ }
+ if (crash_signal_fd >= 0) {
+ fds_to_map.push_back(std::make_pair(
+ crash_signal_fd,
+ kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor));
+ }
+ }
+ if (is_renderer) {
+ const int sandbox_fd =
+ Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
+ fds_to_map.push_back(std::make_pair(
+ sandbox_fd,
+ kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
}
- const int sandbox_fd =
- Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
- fds_to_map.push_back(std::make_pair(sandbox_fd, kSandboxIPCChannel + 3));
#endif // defined(OS_LINUX)
// Actually launch the app.
@@ -126,13 +178,24 @@ class ChildProcessLauncher::Context
ChromeThread::PostTask(
client_thread_id_, FROM_HERE,
NewRunnableMethod(
- this, &ChildProcessLauncher::Context::Notify, handle, zygote));
+ this,
+ &ChildProcessLauncher::Context::Notify,
+#if defined(OS_LINUX)
+ zygote,
+#endif
+ handle));
}
- void Notify(base::ProcessHandle handle, bool zygote) {
+ void Notify(
+#if defined(OS_LINUX)
+ bool zygote,
+#endif
+ base::ProcessHandle handle) {
starting_ = false;
process_.set_handle(handle);
+#if defined(OS_LINUX)
zygote_ = zygote;
+#endif
if (client_) {
client_->OnProcessLaunched();
} else {
@@ -150,24 +213,32 @@ class ChildProcessLauncher::Context
FROM_HERE,
NewRunnableFunction(
&ChildProcessLauncher::Context::TerminateInternal,
- process_.handle(), zygote_));
+#if defined(OS_LINUX)
+ zygote_,
+#endif
+ process_.handle()));
process_.set_handle(base::kNullProcessHandle);
}
- static void TerminateInternal(base::ProcessHandle handle, bool zygote) {
+ static void TerminateInternal(
+#if defined(OS_LINUX)
+ bool zygote,
+#endif
+ base::ProcessHandle handle) {
base::Process process(handle);
// Client has gone away, so just kill the process. Using exit code 0
// means that UMA won't treat this as a crash.
process.Terminate(ResultCodes::NORMAL_EXIT);
// On POSIX, we must additionally reap the child.
#if defined(OS_POSIX)
- if (zygote) {
#if defined(OS_LINUX)
+ if (zygote) {
// If the renderer was created via a zygote, we have to proxy the reaping
// through the zygote process.
Singleton<ZygoteHost>()->EnsureProcessTerminated(handle);
+ } else
#endif // defined(OS_LINUX)
- } else {
+ {
ProcessWatcher::EnsureProcessTerminated(handle);
}
#endif
@@ -178,20 +249,32 @@ class ChildProcessLauncher::Context
ChromeThread::ID client_thread_id_;
base::Process process_;
bool starting_;
+
+#if defined(OS_LINUX)
bool zygote_;
+#endif
};
-ChildProcessLauncher::ChildProcessLauncher(CommandLine* cmd_line,
- IPC::SyncChannel* channel,
- Client* client) {
+ChildProcessLauncher::ChildProcessLauncher(
+#if defined(OS_WIN)
+ const FilePath& exposed_dir,
+#elif defined(OS_POSIX)
+ const base::environment_vector& environ,
+ int ipcfd,
+#endif
+ CommandLine* cmd_line,
+ Client* client) {
context_ = new Context();
-
- int ipcfd = 0;
-#if defined(OS_POSIX)
- ipcfd = channel->GetClientFileDescriptor();
+ context_->Launch(
+#if defined(OS_WIN)
+ exposed_dir,
+#elif defined(OS_POSIX)
+ environ,
+ ipcfd,
#endif
- context_->Launch(cmd_line, ipcfd, client);
+ cmd_line,
+ client);
}
ChildProcessLauncher::~ChildProcessLauncher() {
diff --git a/chrome/browser/child_process_launcher.h b/chrome/browser/child_process_launcher.h
index 7c4202f..d37cb57 100644
--- a/chrome/browser/child_process_launcher.h
+++ b/chrome/browser/child_process_launcher.h
@@ -6,15 +6,11 @@
#define CHROME_BROWSER_CHILD_PROCESS_LAUNCHER_H_
#include "base/basictypes.h"
-#include "base/process.h"
+#include "base/process_util.h"
#include "base/ref_counted.h"
class CommandLine;
-namespace IPC {
-class SyncChannel;
-}
-
// Launches a process asynchronously and notifies the client of the process
// handle when it's available. It's used to avoid blocking the calling thread
// on the OS since often it can take > 100 ms to create the process.
@@ -32,9 +28,15 @@ class ChildProcessLauncher {
// the callback won't be called. If the process is still running by the time
// this object destructs, it will be terminated.
// Takes ownership of cmd_line.
- ChildProcessLauncher(CommandLine* cmd_line,
- IPC::SyncChannel* channel,
- Client* client);
+ ChildProcessLauncher(
+#if defined(OS_WIN)
+ const FilePath& exposed_dir,
+#elif defined(OS_POSIX)
+ const base::environment_vector& environ,
+ int ipcfd,
+#endif
+ CommandLine* cmd_line,
+ Client* client);
~ChildProcessLauncher();
// True if the process is being launched and so the handle isn't available.
diff --git a/chrome/browser/nacl_process_host.cc b/chrome/browser/nacl_process_host.cc
index dbdcb2a..e84d76c 100644
--- a/chrome/browser/nacl_process_host.cc
+++ b/chrome/browser/nacl_process_host.cc
@@ -10,22 +10,13 @@
#include <fcntl.h>
#endif
-#if defined(OS_POSIX)
-#include "base/global_descriptors_posix.h"
-#endif
-#include "base/path_service.h"
-#include "base/process_util.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/nacl_messages.h"
+#include "chrome/common/render_messages.h"
#include "ipc/ipc_switches.h"
-#if defined(OS_WIN)
-#include "chrome/browser/sandbox_policy.h"
-#endif
-
#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
#endif
@@ -34,97 +25,60 @@ NaClProcessHost::NaClProcessHost(
ResourceDispatcherHost *resource_dispatcher_host,
const std::wstring& url)
: ChildProcessHost(NACL_PROCESS, resource_dispatcher_host),
- resource_dispatcher_host_(resource_dispatcher_host) {
+ resource_dispatcher_host_(resource_dispatcher_host),
+ reply_msg_(NULL),
+ descriptor_(0) {
set_name(url);
}
-bool NaClProcessHost::Launch(ResourceMessageFilter* renderer_msg_filter,
+NaClProcessHost::~NaClProcessHost() {
+ if (!reply_msg_)
+ return;
+
+ // OnProcessLaunched didn't get called because the process couldn't launch.
+ // Don't keep the renderer hanging.
+ reply_msg_->set_reply_error();
+ resource_message_filter_->Send(reply_msg_);
+}
+
+bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter,
const int descriptor,
- nacl::FileDescriptor* imc_handle,
- base::ProcessHandle* nacl_process_handle,
- base::ProcessId* nacl_process_id) {
+ IPC::Message* reply_msg) {
#ifdef DISABLE_NACL
NOTIMPLEMENTED() << "Native Client disabled at build time";
return false;
#else
- nacl::Handle pair[2];
- bool success = false;
-
- NATIVE_HANDLE(*imc_handle) = nacl::kInvalidHandle;
- *nacl_process_handle = nacl::kInvalidHandle;
- *nacl_process_id = 0;
// Create a connected socket
- if (nacl::SocketPair(pair) == -1) {
+ if (nacl::SocketPair(pair_) == -1)
return false;
- }
// Launch the process
- success = LaunchSelLdr(renderer_msg_filter, descriptor, pair[1]);
-
- if (!success) {
- nacl::Close(pair[0]);
+ descriptor_ = descriptor;
+ if (!LaunchSelLdr()) {
+ nacl::Close(pair_[0]);
return false;
}
-#if NACL_WINDOWS
- // Duplicate the IMC handle
- DuplicateHandle(base::GetCurrentProcessHandle(),
- reinterpret_cast<HANDLE>(pair[0]),
- renderer_msg_filter->handle(),
- imc_handle,
- GENERIC_READ | GENERIC_WRITE,
- FALSE,
- DUPLICATE_CLOSE_SOURCE);
-
- // Duplicate the process handle
- DuplicateHandle(base::GetCurrentProcessHandle(),
- handle(),
- renderer_msg_filter->handle(),
- nacl_process_handle,
- PROCESS_DUP_HANDLE,
- FALSE,
- 0);
-
-#else
- int flags = fcntl(pair[0], F_GETFD);
- if (flags != -1) {
- flags |= FD_CLOEXEC;
- fcntl(pair[0], F_SETFD, flags);
- }
- // No need to dup the imc_handle - we don't pass it anywhere else so
- // it cannot be closed.
- imc_handle->fd = pair[0];
- imc_handle->auto_close = true;
-
- // We use pid as process handle on Posix
- *nacl_process_handle = handle();
-
-#endif
-
- // Get the pid of the NaCl process
- *nacl_process_id = base::GetProcId(handle());
+ resource_message_filter_ = resource_message_filter;
+ reply_msg_ = reply_msg;
return true;
#endif // DISABLE_NACL
}
-bool NaClProcessHost::LaunchSelLdr(ResourceMessageFilter* renderer_msg_filter,
- const int descriptor,
- const nacl::Handle imc_handle) {
+bool NaClProcessHost::LaunchSelLdr() {
if (!CreateChannel())
return false;
// Build command line for nacl.
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- FilePath exe_path =
- browser_command_line.GetSwitchValuePath(switches::kBrowserSubprocessPath);
- if (exe_path.empty() && !PathService::Get(base::FILE_EXE, &exe_path))
+ FilePath exe_path = GetChildPath();
+ if (exe_path.empty())
return false;
- CommandLine cmd_line(exe_path);
+ CommandLine* cmd_line = new CommandLine(exe_path);
if (logging::DialogsAreSuppressed())
- cmd_line.AppendSwitch(switches::kNoErrorDialogs);
+ cmd_line->AppendSwitch(switches::kNoErrorDialogs);
// Propagate the following switches to the plugin command line (along with
// any associated values) if present in the browser command line.
@@ -142,64 +96,98 @@ bool NaClProcessHost::LaunchSelLdr(ResourceMessageFilter* renderer_msg_filter,
switches::kMemoryProfiling,
};
+ const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
for (size_t i = 0; i < arraysize(switch_names); ++i) {
if (browser_command_line.HasSwitch(switch_names[i])) {
- cmd_line.AppendSwitchWithValue(
+ cmd_line->AppendSwitchWithValue(
switch_names[i],
browser_command_line.GetSwitchValueASCII(switch_names[i]));
}
}
- cmd_line.AppendSwitchWithValue(switches::kProcessType,
- switches::kNaClProcess);
+ cmd_line->AppendSwitchWithValue(switches::kProcessType,
+ switches::kNaClProcess);
- cmd_line.AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
+ ASCIIToWide(channel_id()));
- base::ProcessHandle process = 0;
+ ChildProcessHost::Launch(
#if defined(OS_WIN)
- process = sandbox::StartProcess(&cmd_line);
+ FilePath(),
+#elif defined(OS_POSIX)
+ base::environment_vector(),
+#endif
+ cmd_line);
+
+ return true;
+}
+
+void NaClProcessHost::OnProcessLaunched() {
+ nacl::FileDescriptor imc_handle;
+ base::ProcessHandle nacl_process_handle;
+#if NACL_WINDOWS
+ // Duplicate the IMC handle
+ DuplicateHandle(base::GetCurrentProcessHandle(),
+ reinterpret_cast<HANDLE>(pair_[0]),
+ resource_message_filter_->handle(),
+ &imc_handle,
+ GENERIC_READ | GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_CLOSE_SOURCE);
+
+ // Duplicate the process handle
+ DuplicateHandle(base::GetCurrentProcessHandle(),
+ handle(),
+ resource_message_filter_->handle(),
+ &nacl_process_handle,
+ PROCESS_DUP_HANDLE,
+ FALSE,
+ 0);
+
#else
- base::file_handle_mapping_vector fds_to_map;
- const int ipcfd = channel().GetClientFileDescriptor();
- if (ipcfd > -1)
- fds_to_map.push_back(std::pair<int, int>(
- ipcfd, kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
- base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
+ int flags = fcntl(pair_[0], F_GETFD);
+ if (flags != -1) {
+ flags |= FD_CLOEXEC;
+ fcntl(pair_[0], F_SETFD, flags);
+ }
+ // No need to dup the imc_handle - we don't pass it anywhere else so
+ // it cannot be closed.
+ imc_handle.fd = pair_[0];
+ imc_handle.auto_close = true;
+
+ // We use pid as process handle on Posix
+ nacl_process_handle = handle();
+
#endif
- if (!process)
- return false;
- SetHandle(process);
+ // Get the pid of the NaCl process
+ base::ProcessId nacl_process_id = base::GetProcId(handle());
- // send a message with duplicated imc_handle to sel_ldr
- return SendStartMessage(process, descriptor, imc_handle);
+ ViewHostMsg_LaunchNaCl::WriteReplyParams(
+ reply_msg_, imc_handle, nacl_process_handle, nacl_process_id);
+ resource_message_filter_->Send(reply_msg_);
+ resource_message_filter_ = NULL;
+ reply_msg_ = NULL;
+
+ SendStartMessage();
}
-bool NaClProcessHost::SendStartMessage(base::ProcessHandle process,
- int descriptor,
- nacl::Handle imc_handle) {
+void NaClProcessHost::SendStartMessage() {
nacl::FileDescriptor channel;
#if defined(OS_WIN)
if (!DuplicateHandle(GetCurrentProcess(),
- reinterpret_cast<HANDLE>(imc_handle),
- process,
+ reinterpret_cast<HANDLE>(pair_[1]),
+ handle(),
reinterpret_cast<HANDLE*>(&channel),
GENERIC_READ | GENERIC_WRITE,
FALSE, DUPLICATE_CLOSE_SOURCE)) {
- return false;
+ return;
}
#else
- channel.fd = dup(imc_handle);
+ channel.fd = dup(pair_[1]);
channel.auto_close = true;
#endif
- NaClProcessMsg_Start* msg = new NaClProcessMsg_Start(descriptor,
- channel);
-
- if (!Send(msg)) {
- return false;
- }
- return true;
+ Send(new NaClProcessMsg_Start(descriptor_, channel));
}
void NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
diff --git a/chrome/browser/nacl_process_host.h b/chrome/browser/nacl_process_host.h
index eb38631..8159836 100644
--- a/chrome/browser/nacl_process_host.h
+++ b/chrome/browser/nacl_process_host.h
@@ -6,6 +6,8 @@
#define CHROME_BROWSER_NACL_PROCESS_HOST_H_
#include "build/build_config.h"
+
+#include "base/ref_counted.h"
#include "chrome/common/child_process_host.h"
#include "chrome/common/nacl_types.h"
#include "native_client/src/shared/imc/nacl_imc.h"
@@ -22,25 +24,21 @@ class NaClProcessHost : public ChildProcessHost {
public:
NaClProcessHost(ResourceDispatcherHost *resource_dispatcher_host,
const std::wstring& url);
- ~NaClProcessHost() {}
+ ~NaClProcessHost();
// Initialize the new NaCl process, returning true on success.
- bool Launch(ResourceMessageFilter* renderer_msg_filter,
+ bool Launch(ResourceMessageFilter* resource_message_filter,
const int descriptor,
- nacl::FileDescriptor* handle,
- base::ProcessHandle* nacl_process_handle,
- base::ProcessId* nacl_process_id);
+ IPC::Message* reply_msg);
virtual void OnMessageReceived(const IPC::Message& msg);
private:
- bool LaunchSelLdr(ResourceMessageFilter* renderer_msg_filter,
- const int descriptor,
- const nacl::Handle handle);
+ bool LaunchSelLdr();
+
+ void SendStartMessage();
- bool SendStartMessage(base::ProcessHandle process,
- int descriptor,
- nacl::Handle handle);
+ virtual void OnProcessLaunched();
// ResourceDispatcherHost::Receiver implementation:
virtual URLRequestContext* GetRequestContext(
@@ -52,6 +50,19 @@ class NaClProcessHost : public ChildProcessHost {
private:
ResourceDispatcherHost* resource_dispatcher_host_;
+ // The ResourceMessageFilter that requested this NaCl process. We use this
+ // for sending the reply once the process has started.
+ scoped_refptr<ResourceMessageFilter> resource_message_filter_;
+
+ // The reply message to send.
+ IPC::Message* reply_msg_;
+
+ // The socket pair for the NaCl process.
+ nacl::Handle pair_[2];
+
+ // The NaCl specific descriptor for this process.
+ int descriptor_;
+
DISALLOW_COPY_AND_ASSIGN(NaClProcessHost);
};
diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc
index e09807b..422c095 100644
--- a/chrome/browser/plugin_process_host.cc
+++ b/chrome/browser/plugin_process_host.cc
@@ -19,7 +19,6 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
-#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/chrome_plugin_browsing_context.h"
@@ -29,14 +28,12 @@
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/render_messages.h"
-#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_switches.h"
#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
@@ -45,19 +42,11 @@
#if defined(OS_WIN)
#include "app/win_util.h"
-#include "chrome/browser/sandbox_policy.h"
-#include "sandbox/src/sandbox.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#endif
-#if defined(OS_POSIX)
-#include "base/global_descriptors_posix.h"
-#include "ipc/ipc_channel_posix.h"
-#endif
-
#if defined(OS_LINUX)
#include "app/gfx/gtk_native_view_id_manager.h"
-#include "chrome/browser/crash_handler_host_linux.h"
#endif
#if defined(OS_MACOSX)
@@ -353,16 +342,16 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
if (exe_path.empty())
return false;
- CommandLine cmd_line(exe_path);
+ CommandLine* cmd_line = new CommandLine(exe_path);
// Put the process type and plugin path first so they're easier to see
// in process listings using native process management tools.
- cmd_line.AppendSwitchWithValue(switches::kProcessType,
- switches::kPluginProcess);
- cmd_line.AppendSwitchWithValue(switches::kPluginPath,
- info.path.ToWStringHack());
+ cmd_line->AppendSwitchWithValue(switches::kProcessType,
+ switches::kPluginProcess);
+ cmd_line->AppendSwitchWithValue(switches::kPluginPath,
+ info.path.ToWStringHack());
if (logging::DialogsAreSuppressed())
- cmd_line.AppendSwitch(switches::kNoErrorDialogs);
+ cmd_line->AppendSwitch(switches::kNoErrorDialogs);
// Propagate the following switches to the plugin command line (along with
// any associated values) if present in the browser command line
@@ -390,7 +379,7 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
for (size_t i = 0; i < arraysize(switch_names); ++i) {
if (browser_command_line.HasSwitch(switch_names[i])) {
- cmd_line.AppendSwitchWithValue(
+ cmd_line->AppendSwitchWithValue(
switch_names[i],
browser_command_line.GetSwitchValueASCII(switch_names[i]));
}
@@ -400,62 +389,26 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
std::wstring plugin_launcher =
browser_command_line.GetSwitchValue(switches::kPluginLauncher);
if (!plugin_launcher.empty())
- cmd_line.PrependWrapper(plugin_launcher);
+ cmd_line->PrependWrapper(plugin_launcher);
if (!locale.empty()) {
// Pass on the locale so the null plugin will use the right language in the
// prompt to install the desired plugin.
- cmd_line.AppendSwitchWithValue(switches::kLang, locale);
+ cmd_line->AppendSwitchWithValue(switches::kLang, locale);
}
// Gears requires the data dir to be available on startup.
std::wstring data_dir =
PluginService::GetInstance()->GetChromePluginDataDir().ToWStringHack();
DCHECK(!data_dir.empty());
- cmd_line.AppendSwitchWithValue(switches::kPluginDataDir, data_dir);
-
- cmd_line.AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
-
- SetCrashReporterCommandLine(&cmd_line);
-
- base::ProcessHandle process = 0;
-#if defined(OS_WIN)
- process = sandbox::StartProcess(&cmd_line);
-#else
- process = InitHelperPosix(cmd_line);
-#endif // OS_WIN
-
- if (!process)
- return false;
- SetHandle(process);
+ cmd_line->AppendSwitchWithValue(switches::kPluginDataDir, data_dir);
- FilePath gears_path;
- if (PathService::Get(chrome::FILE_GEARS_PLUGIN, &gears_path)) {
- FilePath::StringType gears_path_lc = StringToLowerASCII(gears_path.value());
- FilePath::StringType plugin_path_lc =
- StringToLowerASCII(info.path.value());
- if (plugin_path_lc == gears_path_lc) {
- // Give Gears plugins "background" priority. See
- // http://b/issue?id=1280317.
- SetProcessBackgrounded();
- }
- }
+ cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
+ ASCIIToWide(channel_id()));
- return true;
-}
+ SetCrashReporterCommandLine(cmd_line);
#if defined(OS_POSIX)
-base::ProcessHandle PluginProcessHost::InitHelperPosix(
- const CommandLine& cmd_line) {
- base::ProcessHandle process = 0;
- // This code is duplicated with browser_render_process_host.cc, but
- // there's not a good place to de-duplicate it.
- base::file_handle_mapping_vector fds_to_map;
- const int ipcfd = channel().GetClientFileDescriptor();
- if (ipcfd > -1)
- fds_to_map.push_back(std::pair<int, int>(
- ipcfd, kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
base::environment_vector env;
#if defined(OS_MACOSX)
// Add our interposing library for Carbon. This is stripped back out in
@@ -470,19 +423,32 @@ base::ProcessHandle PluginProcessHost::InitHelperPosix(
env.push_back(std::pair<const char*, const char*>(
plugin_interpose_strings::kDYLDInsertLibrariesKey,
interpose_list.c_str()));
-#elif defined(OS_LINUX)
- const int crash_signal_fd =
- Singleton<PluginCrashHandlerHostLinux>()->GetDeathSignalSocket();
- if (crash_signal_fd >= 0) {
- fds_to_map.push_back(std::pair<int, uint32_t>(crash_signal_fd,
- kCrashDumpSignal + 3));
+#endif
+#endif
+
+ Launch(
+#if defined(OS_WIN)
+ FilePath(),
+#elif defined(OS_POSIX)
+ env,
+#endif
+ cmd_line);
+
+ return true;
+}
+
+void PluginProcessHost::OnProcessLaunched() {
+ FilePath gears_path;
+ if (PathService::Get(chrome::FILE_GEARS_PLUGIN, &gears_path)) {
+ FilePath::StringType gears_path_lc = StringToLowerASCII(gears_path.value());
+ FilePath::StringType plugin_path_lc =
+ StringToLowerASCII(info_.path.value());
+ if (plugin_path_lc == gears_path_lc) {
+ // Give Gears plugins "background" priority. See http://b/1280317.
+ SetProcessBackgrounded();
+ }
}
-#endif // OS_MACOSX
- if (!base::LaunchApp(cmd_line.argv(), env, fds_to_map, false, &process))
- process = 0;
- return process;
}
-#endif // OS_POSIX
void PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(PluginProcessHost, msg)
diff --git a/chrome/browser/plugin_process_host.h b/chrome/browser/plugin_process_host.h
index c2a240d..bc9feec 100644
--- a/chrome/browser/plugin_process_host.h
+++ b/chrome/browser/plugin_process_host.h
@@ -99,6 +99,9 @@ class PluginProcessHost : public ChildProcessHost,
void RequestPluginChannel(ResourceMessageFilter* renderer_message_filter,
const std::string& mime_type,
IPC::Message* reply_msg);
+
+ virtual void OnProcessLaunched();
+
// Message handlers.
void OnChannelCreated(const IPC::ChannelHandle& channel_handle);
void OnGetPluginFinderUrl(std::string* plugin_finder_url);
@@ -115,10 +118,6 @@ class PluginProcessHost : public ChildProcessHost,
gfx::NativeWindow caller_window);
#endif
-#if defined(OS_POSIX)
- base::ProcessHandle InitHelperPosix(const CommandLine& cmd_line);
-#endif
-
#if defined(OS_LINUX)
void OnMapNativeViewId(gfx::NativeViewId id, gfx::PluginWindowHandle* output);
#endif
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index b921f31..ef72346 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -19,7 +19,6 @@
#include "base/command_line.h"
#include "base/field_trial.h"
#include "base/logging.h"
-#include "base/process_util.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread.h"
@@ -301,16 +300,21 @@ bool BrowserRenderProcessHost::Init(bool is_extensions_process) {
} else {
// Build command line for renderer, we have to quote the executable name to
// deal with spaces.
- scoped_ptr<CommandLine> cmd_line(new CommandLine(renderer_path));
+ CommandLine* cmd_line = new CommandLine(renderer_path);
cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
ASCIIToWide(channel_id));
- if (is_extensions_process)
- cmd_line->AppendSwitch(switches::kEnableDatabases);
- AppendRendererCommandLine(cmd_line.get());
+ AppendRendererCommandLine(cmd_line);
// Spawn the child process asynchronously to avoid blocking the UI thread.
child_process_.reset(new ChildProcessLauncher(
- cmd_line.release(), channel_.get(), this));
+#if defined(OS_WIN)
+ FilePath(),
+#elif defined(POSIX)
+ base::environment_vector(),
+ channel_->GetClientFileDescriptor(),
+#endif
+ cmd_line,
+ this));
fast_shutdown_started_ = false;
}
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc
index 76ff9f5..e0b3832 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -165,21 +165,36 @@ static bool GetNewTextDirection(WebTextDirection* direction) {
class NotifyPluginProcessHostTask : public Task {
public:
NotifyPluginProcessHostTask(HWND window, HWND parent)
- : window_(window), parent_(parent) { }
+ : window_(window), parent_(parent), tries_(kMaxTries) { }
private:
void Run() {
DWORD plugin_process_id;
+ bool found_starting_plugin_process = false;
GetWindowThreadProcessId(window_, &plugin_process_id);
for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
!iter.Done(); ++iter) {
PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
+ if (!plugin->handle()) {
+ found_starting_plugin_process = true;
+ continue;
+ }
if (base::GetProcId(plugin->handle()) == plugin_process_id) {
plugin->AddWindow(parent_);
return;
}
}
+ if (found_starting_plugin_process) {
+ // A plugin process has started but we don't have its handle yet. Since
+ // it's most likely the one for this plugin, try a few more times after a
+ // delay.
+ if (tries_--) {
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, this, kTryDelayMs);
+ return;
+ }
+ }
+
// The plugin process might have died in the time to execute the task, don't
// leak the HWND.
PostMessage(parent_, WM_CLOSE, 0, 0);
@@ -187,6 +202,14 @@ class NotifyPluginProcessHostTask : public Task {
HWND window_; // Plugin HWND, created and destroyed in the plugin process.
HWND parent_; // Parent HWND, created and destroyed on the browser UI thread.
+
+ int tries_;
+
+ // How many times we try to find a PluginProcessHost whose process matches
+ // the HWND.
+ static const int kMaxTries = 5;
+ // How long to wait between each try.
+ static const int kTryDelayMs = 200;
};
// Windows callback for OnDestroy to detach the plugin windows.
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index ba34532..f4dd68f 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -308,7 +308,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
OnReceiveContextMenuMsg(msg))
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPlugin,
OnOpenChannelToPlugin)
- IPC_MESSAGE_HANDLER(ViewHostMsg_LaunchNaCl, OnLaunchNaCl)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_LaunchNaCl, OnLaunchNaCl)
IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker)
IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker)
IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentDetached, OnDocumentDetached)
@@ -635,18 +635,10 @@ void ResourceMessageFilter::OnOpenChannelToPlugin(const GURL& url,
this, url, mime_type, locale, reply_msg);
}
-void ResourceMessageFilter::OnLaunchNaCl(const std::wstring& url,
- int channel_descriptor,
- nacl::FileDescriptor* imc_handle,
- base::ProcessHandle* nacl_process_handle,
- base::ProcessId* nacl_process_id) {
- NaClProcessHost* nacl_host = new NaClProcessHost(resource_dispatcher_host_,
- url);
- nacl_host->Launch(this,
- channel_descriptor,
- imc_handle,
- nacl_process_handle,
- nacl_process_id);
+void ResourceMessageFilter::OnLaunchNaCl(
+ const std::wstring& url, int channel_descriptor, IPC::Message* reply_msg) {
+ NaClProcessHost* host = new NaClProcessHost(resource_dispatcher_host_, url);
+ host->Launch(this, channel_descriptor, reply_msg);
}
void ResourceMessageFilter::OnCreateWorker(const GURL& url,
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index 31f87d4..cb7686e 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -165,9 +165,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
IPC::Message* reply_msg);
void OnLaunchNaCl(const std::wstring& url,
int channel_descriptor,
- nacl::FileDescriptor* handle,
- base::ProcessHandle* nacl_process_handle,
- base::ProcessId* nacl_process_id);
+ IPC::Message* reply_msg);
void OnCreateWorker(const GURL& url,
bool is_shared,
const string16& name,
diff --git a/chrome/browser/task_manager_resource_providers.cc b/chrome/browser/task_manager_resource_providers.cc
index 38d0687..4a3a624 100644
--- a/chrome/browser/task_manager_resource_providers.cc
+++ b/chrome/browser/task_manager_resource_providers.cc
@@ -376,13 +376,13 @@ void TaskManagerChildProcessResourceProvider::StartUpdating() {
DCHECK(!updating_);
updating_ = true;
- // Register for notifications to get new plugin processes.
+ // Register for notifications to get new child processes.
registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
NotificationService::AllSources());
- // Get the existing plugins
+ // Get the existing child processes.
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableMethod(
@@ -482,7 +482,9 @@ void TaskManagerChildProcessResourceProvider::AddToTaskManager(
// The ChildProcessInfo::Iterator has to be used from the IO thread.
void TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo() {
for (ChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
- existing_child_process_info_.push_back(**iter);
+ // Only add processes which are already started, since we need their handle.
+ if ((*iter)->handle() != base::kNullProcessHandle)
+ existing_child_process_info_.push_back(**iter);
}
// Now notify the UI thread that we have retrieved information about child
// processes.
diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc
index 35bc7f0..9f7d647 100644
--- a/chrome/browser/utility_process_host.cc
+++ b/chrome/browser/utility_process_host.cc
@@ -9,21 +9,10 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
-#include "base/string_util.h"
-#include "base/task.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/render_messages.h"
#include "ipc/ipc_switches.h"
-#if defined(OS_WIN)
-#include "chrome/browser/sandbox_policy.h"
-#elif defined(OS_POSIX)
-#include "base/global_descriptors_posix.h"
-#include "ipc/ipc_descriptors.h"
-#endif
-
UtilityProcessHost::UtilityProcessHost(ResourceDispatcherHost* rdh,
Client* client,
ChromeThread::ID client_thread_id)
@@ -86,30 +75,22 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
return false;
}
- CommandLine cmd_line(exe_path);
- cmd_line.AppendSwitchWithValue(switches::kProcessType,
- switches::kUtilityProcess);
- cmd_line.AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ CommandLine* cmd_line = new CommandLine(exe_path);
+ cmd_line->AppendSwitchWithValue(switches::kProcessType,
+ switches::kUtilityProcess);
+ cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
+ ASCIIToWide(channel_id()));
// Pass on the browser locale.
std::string locale = l10n_util::GetApplicationLocale(L"");
- cmd_line.AppendSwitchWithValue(switches::kLang, ASCIIToWide(locale));
+ cmd_line->AppendSwitchWithValue(switches::kLang, ASCIIToWide(locale));
- SetCrashReporterCommandLine(&cmd_line);
+ SetCrashReporterCommandLine(cmd_line);
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- if (browser_command_line.HasSwitch(switches::kChromeFrame)) {
- cmd_line.AppendSwitch(switches::kChromeFrame);
- }
+ if (browser_command_line.HasSwitch(switches::kChromeFrame))
+ cmd_line->AppendSwitch(switches::kChromeFrame);
- base::ProcessHandle process;
-#if defined(OS_WIN)
- if (exposed_dir.empty()) {
- process = sandbox::StartProcess(&cmd_line);
- } else {
- process = sandbox::StartProcessWithAccess(&cmd_line, exposed_dir);
- }
-#else
+#if defined(OS_POSIX)
// TODO(port): Sandbox this on Linux. Also, zygote this to work with
// Linux updating.
bool has_cmd_prefix = browser_command_line.HasSwitch(
@@ -117,27 +98,21 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
if (has_cmd_prefix) {
// launch the utility child process with some prefix (usually "xterm -e gdb
// --args").
- cmd_line.PrependWrapper(browser_command_line.GetSwitchValue(
+ cmd_line->PrependWrapper(browser_command_line.GetSwitchValue(
switches::kUtilityCmdPrefix));
}
- cmd_line.AppendSwitchWithValue(switches::kUtilityProcessAllowedDir,
- exposed_dir.value().c_str());
-
- // This code is duplicated with browser_render_process_host.cc and
- // plugin_process_host.cc, but there's not a good place to de-duplicate it.
- // Maybe we can merge this into sandbox::StartProcess which will set up
- // everything before calling LaunchApp?
- base::file_handle_mapping_vector fds_to_map;
- const int ipcfd = channel().GetClientFileDescriptor();
- if (ipcfd > -1)
- fds_to_map.push_back(std::pair<int, int>(
- ipcfd, kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
- base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
+ cmd_line->AppendSwitchWithValue(switches::kUtilityProcessAllowedDir,
+ exposed_dir.value().c_str());
#endif
- if (!process)
- return false;
- SetHandle(process);
+
+ Launch(
+#if defined(OS_WIN)
+ exposed_dir,
+#elif defined(OS_POSIX)
+ base::environment_vector(),
+#endif
+ cmd_line);
return true;
}
@@ -148,14 +123,10 @@ void UtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
NewRunnableMethod(client_.get(), &Client::OnMessageReceived, message));
}
-void UtilityProcessHost::OnChannelError() {
- bool child_exited;
- bool did_crash = base::DidProcessCrash(&child_exited, handle());
- if (did_crash) {
- ChromeThread::PostTask(
- client_thread_id_, FROM_HERE,
- NewRunnableMethod(client_.get(), &Client::OnProcessCrashed));
- }
+void UtilityProcessHost::OnProcessCrashed() {
+ ChromeThread::PostTask(
+ client_thread_id_, FROM_HERE,
+ NewRunnableMethod(client_.get(), &Client::OnProcessCrashed));
}
void UtilityProcessHost::Client::OnMessageReceived(
diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h
index 8995210..a1929fe 100644
--- a/chrome/browser/utility_process_host.h
+++ b/chrome/browser/utility_process_host.h
@@ -109,7 +109,7 @@ class UtilityProcessHost : public ChildProcessHost {
void OnMessageReceived(const IPC::Message& message);
// ChildProcessHost:
- virtual void OnChannelError();
+ virtual void OnProcessCrashed();
virtual bool CanShutdown() { return true; }
virtual URLRequestContext* GetRequestContext(
uint32 request_id,
diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc
index b1e7e18f..0f6786b 100644
--- a/chrome/browser/worker_host/worker_process_host.cc
+++ b/chrome/browser/worker_host/worker_process_host.cc
@@ -9,12 +9,7 @@
#include "base/command_line.h"
#include "base/debug_util.h"
-#if defined(OS_POSIX)
-#include "base/global_descriptors_posix.h"
-#endif
#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/child_process_security_policy.h"
@@ -26,18 +21,12 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
#include "chrome/common/notification_service.h"
-#include "chrome/common/process_watcher.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/result_codes.h"
#include "chrome/common/worker_messages.h"
-#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_switches.h"
#include "net/base/registry_controlled_domain.h"
-#if defined(OS_WIN)
-#include "chrome/browser/sandbox_policy.h"
-#endif
-
// Notifies RenderViewHost that one or more worker objects crashed.
class WorkerCrashTask : public Task {
public:
@@ -94,45 +83,35 @@ bool WorkerProcessHost::Init() {
if (exe_path.empty())
return false;
- CommandLine cmd_line(exe_path);
- cmd_line.AppendSwitchWithValue(switches::kProcessType,
- switches::kWorkerProcess);
- cmd_line.AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
- SetCrashReporterCommandLine(&cmd_line);
+ CommandLine* cmd_line = new CommandLine(exe_path);
+ cmd_line->AppendSwitchWithValue(switches::kProcessType,
+ switches::kWorkerProcess);
+ cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
+ ASCIIToWide(channel_id()));
+ SetCrashReporterCommandLine(cmd_line);
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableNativeWebWorkers)) {
- cmd_line.AppendSwitch(switches::kEnableNativeWebWorkers);
+ cmd_line->AppendSwitch(switches::kEnableNativeWebWorkers);
}
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWebWorkerShareProcesses)) {
- cmd_line.AppendSwitch(switches::kWebWorkerShareProcesses);
+ cmd_line->AppendSwitch(switches::kWebWorkerShareProcesses);
}
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWorkerStartupDialog)) {
- cmd_line.AppendSwitch(switches::kWorkerStartupDialog);
+ cmd_line->AppendSwitch(switches::kWorkerStartupDialog);
}
- base::ProcessHandle process;
+ Launch(
#if defined(OS_WIN)
- process = sandbox::StartProcess(&cmd_line);
-#else
- // This code is duplicated with browser_render_process_host.cc, but
- // there's not a good place to de-duplicate it.
- base::file_handle_mapping_vector fds_to_map;
- const int ipcfd = channel().GetClientFileDescriptor();
- if (ipcfd > -1) {
- fds_to_map.push_back(std::pair<int, int>(
- ipcfd, kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
- }
- base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
+ FilePath(),
+#elif defined(OS_POSIX)
+ base::environment_vector(),
#endif
- if (!process)
- return false;
- SetHandle(process);
+ cmd_line);
ChildProcessSecurityPolicy::GetInstance()->Add(id());
diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc
index d4a9eda..745d7a0 100644
--- a/chrome/common/child_process_host.cc
+++ b/chrome/common/child_process_host.cc
@@ -79,9 +79,6 @@ ChildProcessHost::~ChildProcessHost() {
Singleton<ChildProcessList>::get()->remove(this);
resource_dispatcher_host_->CancelRequestsForProcess(id());
-
- if (handle())
- ProcessWatcher::EnsureProcessTerminated(handle());
}
// static
@@ -124,6 +121,24 @@ void ChildProcessHost::SetCrashReporterCommandLine(CommandLine* command_line) {
#endif // OS_MACOSX
}
+void ChildProcessHost::Launch(
+#if defined(OS_WIN)
+ const FilePath& exposed_dir,
+#elif defined(OS_POSIX)
+ const base::environment_vector& environ,
+#endif
+ CommandLine* cmd_line) {
+ child_process_.reset(new ChildProcessLauncher(
+#if defined(OS_WIN)
+ exposed_dir,
+#elif defined(OS_POSIX)
+ environ,
+ channel_->GetClientFileDescriptor(),
+#endif
+ cmd_line,
+ &listener_));
+}
+
bool ChildProcessHost::CreateChannel() {
channel_id_ = GenerateRandomChannelID(this);
channel_.reset(new IPC::Channel(
@@ -136,11 +151,6 @@ bool ChildProcessHost::CreateChannel() {
return true;
}
-void ChildProcessHost::SetHandle(base::ProcessHandle process) {
- DCHECK(!handle());
- set_handle(process);
-}
-
void ChildProcessHost::InstanceCreated() {
Notify(NotificationType::CHILD_INSTANCE_CREATED);
}
@@ -159,19 +169,16 @@ void ChildProcessHost::Notify(NotificationType type) {
}
void ChildProcessHost::OnChildDied() {
- DCHECK(handle());
-
- bool did_crash = base::DidProcessCrash(NULL, handle());
- if (did_crash) {
- // Report that this child process crashed.
- Notify(NotificationType::CHILD_PROCESS_CRASHED);
+ if (child_process_->GetHandle()) {
+ bool did_crash = child_process_->DidProcessCrash();
+ if (did_crash) {
+ OnProcessCrashed();
+ // Report that this child process crashed.
+ Notify(NotificationType::CHILD_PROCESS_CRASHED);
+ }
+ // Notify in the main loop of the disconnection.
+ Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
}
- // Notify in the main loop of the disconnection.
- Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
-
- // On POSIX, once we've called DidProcessCrash, handle() is no longer
- // valid. Ensure the destructor doesn't try to use it.
- set_handle(base::kNullProcessHandle);
delete this;
}
@@ -241,6 +248,16 @@ void ChildProcessHost::ListenerHook::OnChannelError() {
host_->OnChildDied();
}
+void ChildProcessHost::ListenerHook::OnProcessLaunched() {
+ if (!host_->child_process_->GetHandle()) {
+ delete this;
+ return;
+ }
+
+ host_->set_handle(host_->child_process_->GetHandle());
+ host_->OnProcessLaunched();
+}
+
ChildProcessHost::Iterator::Iterator()
: all_(true), type_(UNKNOWN_PROCESS) {
diff --git a/chrome/common/child_process_host.h b/chrome/common/child_process_host.h
index a79eaf2..94bdafd 100644
--- a/chrome/common/child_process_host.h
+++ b/chrome/common/child_process_host.h
@@ -13,6 +13,7 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/child_process_launcher.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "ipc/ipc_channel.h"
@@ -25,7 +26,8 @@ class NotificationType;
// [Browser]RenderProcessHost is the main exception that doesn't derive from
// this class. That project lives on the UI thread.
class ChildProcessHost : public ResourceDispatcherHost::Receiver,
- public IPC::Channel::Listener {
+ public IPC::Channel::Listener,
+ public ChildProcessLauncher::Client {
public:
virtual ~ChildProcessHost();
@@ -70,16 +72,21 @@ class ChildProcessHost : public ResourceDispatcherHost::Receiver,
ChildProcessHost(ProcessType type,
ResourceDispatcherHost* resource_dispatcher_host);
+ // Derived classes call this to launch the child process asynchronously.
+ void Launch(
+#if defined(OS_WIN)
+ const FilePath& exposed_dir,
+#elif defined(OS_POSIX)
+ const base::environment_vector& environ,
+#endif
+ CommandLine* cmd_line);
+
// Derived classes return true if it's ok to shut down the child process.
virtual bool CanShutdown() = 0;
// Creates the IPC channel. Returns true iff it succeeded.
bool CreateChannel();
- // Once the subclass gets a handle to the process, it needs to tell
- // ChildProcessHost using this function.
- void SetHandle(base::ProcessHandle handle);
-
// Notifies us that an instance has been created on this child process.
void InstanceCreated();
@@ -88,11 +95,15 @@ class ChildProcessHost : public ResourceDispatcherHost::Receiver,
virtual void OnChannelConnected(int32 peer_pid) { }
virtual void OnChannelError() { }
+ // ChildProcessLauncher::Client implementation.
+ virtual void OnProcessLaunched() {}
+
+ // Derived classes can override this to know if the process crashed.
+ virtual void OnProcessCrashed() {}
+
bool opening_channel() { return opening_channel_; }
const std::string& channel_id() { return channel_id_; }
- const IPC::Channel& channel() const { return *channel_; }
-
private:
// Sends the given notification to the notification service on the UI thread.
void Notify(NotificationType type);
@@ -103,28 +114,24 @@ class ChildProcessHost : public ResourceDispatcherHost::Receiver,
// By using an internal class as the IPC::Channel::Listener, we can intercept
// OnMessageReceived/OnChannelConnected and do our own processing before
// calling the subclass' implementation.
- class ListenerHook : public IPC::Channel::Listener {
+ class ListenerHook : public IPC::Channel::Listener,
+ public ChildProcessLauncher::Client {
public:
explicit ListenerHook(ChildProcessHost* host);
virtual void OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelConnected(int32 peer_pid);
virtual void OnChannelError();
+ virtual void OnProcessLaunched();
private:
ChildProcessHost* host_;
};
ListenerHook listener_;
-
ResourceDispatcherHost* resource_dispatcher_host_;
-
- // True while we're waiting the channel to be opened.
- bool opening_channel_;
-
- // The IPC::Channel.
+ bool opening_channel_; // True while we're waiting the channel to be opened.
scoped_ptr<IPC::Channel> channel_;
-
- // IPC Channel's id.
std::string channel_id_;
+ scoped_ptr<ChildProcessLauncher> child_process_;
};
#endif // CHROME_COMMON_CHILD_PROCESS_HOST_H_
diff --git a/chrome/worker/worker_uitest.cc b/chrome/worker/worker_uitest.cc
index f1a0a59..cbee62b 100644
--- a/chrome/worker/worker_uitest.cc
+++ b/chrome/worker/worker_uitest.cc
@@ -271,8 +271,7 @@ TEST_F(WorkerTest, LimitPerPage) {
ASSERT_TRUE(tab.get());
ASSERT_TRUE(tab->NavigateToURL(url));
- EXPECT_EQ(max_workers_per_tab + 1 + (UITest::in_process_renderer() ? 0 : 1),
- UITest::GetBrowserProcessCount());
+ ASSERT_TRUE(WaitForProcessCountToBe(1, max_workers_per_tab));
}
#endif