diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-21 21:15:09 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-21 21:15:09 +0000 |
commit | b7315211fa8a8468102ac3675f21c875a6c83d0b (patch) | |
tree | 02d499f93080e86990cae70d40732ebf5dfe6677 | |
parent | df0dcd4a244db43f760872c3e607e642ccde2a25 (diff) | |
download | chromium_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.cc | 155 | ||||
-rw-r--r-- | chrome/browser/child_process_launcher.h | 18 | ||||
-rw-r--r-- | chrome/browser/nacl_process_host.cc | 198 | ||||
-rw-r--r-- | chrome/browser/nacl_process_host.h | 33 | ||||
-rw-r--r-- | chrome/browser/plugin_process_host.cc | 108 | ||||
-rw-r--r-- | chrome/browser/plugin_process_host.h | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.cc | 16 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_win.cc | 25 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 18 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 4 | ||||
-rw-r--r-- | chrome/browser/task_manager_resource_providers.cc | 8 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.cc | 79 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.h | 2 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_process_host.cc | 49 | ||||
-rw-r--r-- | chrome/common/child_process_host.cc | 57 | ||||
-rw-r--r-- | chrome/common/child_process_host.h | 39 | ||||
-rw-r--r-- | chrome/worker/worker_uitest.cc | 3 |
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 |