diff options
27 files changed, 308 insertions, 370 deletions
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc index e4d5776..c2aa4ec 100644 --- a/chrome/browser/automation/testing_automation_provider.cc +++ b/chrome/browser/automation/testing_automation_provider.cc @@ -117,6 +117,7 @@ #include "content/browser/plugin_service.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/tab_contents/interstitial_page.h" +#include "content/common/child_process_host.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/common_param_traits.h" diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.cc b/chrome/browser/nacl_host/nacl_broker_host_win.cc index 8bd6077..0c05a8d 100644 --- a/chrome/browser/nacl_host/nacl_broker_host_win.cc +++ b/chrome/browser/nacl_host/nacl_broker_host_win.cc @@ -14,6 +14,7 @@ #include "chrome/common/logging_chrome.h" #include "chrome/common/nacl_cmd_line.h" #include "chrome/common/nacl_messages.h" +#include "content/common/child_process_host.h" NaClBrokerHost::NaClBrokerHost() : BrowserChildProcessHost(content::PROCESS_TYPE_NACL_BROKER), @@ -25,7 +26,7 @@ NaClBrokerHost::~NaClBrokerHost() { bool NaClBrokerHost::Init() { // Create the channel that will be used for communicating with the broker. - if (!CreateChannel()) + if (!child_process_host()->CreateChannel()) return false; // Create the path to the nacl broker/loader executable. @@ -39,7 +40,8 @@ bool NaClBrokerHost::Init() { cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kNaClBrokerProcess); - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, + child_process_host()->channel_id()); if (logging::DialogsAreSuppressed()) cmd_line->AppendSwitch(switches::kNoErrorDialogs); diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc index c84f416..46a030c 100644 --- a/chrome/browser/nacl_host/nacl_process_host.cc +++ b/chrome/browser/nacl_host/nacl_process_host.cc @@ -23,6 +23,7 @@ #include "chrome/common/nacl_messages.h" #include "chrome/common/render_messages.h" #include "chrome/browser/renderer_host/chrome_render_message_filter.h" +#include "content/common/child_process_host.h" #include "ipc/ipc_switches.h" #include "native_client/src/shared/imc/nacl_imc.h" @@ -116,6 +117,21 @@ NaClProcessHost::NaClProcessHost(const std::wstring& url) } NaClProcessHost::~NaClProcessHost() { + int exit_code; + GetChildTerminationStatus(&exit_code); + std::string message = + base::StringPrintf("NaCl process exited with status %i (0x%x)", + exit_code, exit_code); + if (exit_code == 0) { + LOG(INFO) << message; + } else { + LOG(ERROR) << message; + } + +#if defined(OS_WIN) + NaClBrokerService::GetInstance()->OnLoaderDied(); +#endif + for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) { if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) { LOG(ERROR) << "nacl::Close() failed"; @@ -212,7 +228,7 @@ bool NaClProcessHost::Launch( } bool NaClProcessHost::LaunchSelLdr() { - if (!CreateChannel()) + if (!child_process_host()->CreateChannel()) return false; CommandLine::StringType nacl_loader_prefix; @@ -230,14 +246,15 @@ bool NaClProcessHost::LaunchSelLdr() { // to accomodate this request will exist in the child process' address // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and // http://code.google.com/p/nativeclient/issues/detail?id=2043. - int flags = CHILD_NO_PIE; + int flags = ChildProcessHost::CHILD_NO_PIE; #elif defined(OS_LINUX) - int flags = nacl_loader_prefix.empty() ? CHILD_ALLOW_SELF : CHILD_NORMAL; + int flags = nacl_loader_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF : + ChildProcessHost::CHILD_NORMAL; #else - int flags = CHILD_NORMAL; + int flags = ChildProcessHost::CHILD_NORMAL; #endif - FilePath exe_path = GetChildPath(flags); + FilePath exe_path = ChildProcessHost::GetChildPath(flags); if (exe_path.empty()) return false; @@ -246,7 +263,8 @@ bool NaClProcessHost::LaunchSelLdr() { cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kNaClLoaderProcess); - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, + child_process_host()->channel_id()); if (logging::DialogsAreSuppressed()) cmd_line->AppendSwitch(switches::kNoErrorDialogs); @@ -257,7 +275,7 @@ bool NaClProcessHost::LaunchSelLdr() { #if defined(OS_WIN) if (RunningOnWOW64()) { return NaClBrokerService::GetInstance()->LaunchLoader( - this, ASCIIToWide(channel_id())); + this, ASCIIToWide(child_process_host()->channel_id())); } else { BrowserChildProcessHost::Launch(FilePath(), cmd_line); } @@ -282,24 +300,6 @@ base::TerminationStatus NaClProcessHost::GetChildTerminationStatus( return BrowserChildProcessHost::GetChildTerminationStatus(exit_code); } -void NaClProcessHost::OnChildDied() { - int exit_code; - GetChildTerminationStatus(&exit_code); - std::string message = - base::StringPrintf("NaCl process exited with status %i (0x%x)", - exit_code, exit_code); - if (exit_code == 0) { - LOG(INFO) << message; - } else { - LOG(ERROR) << message; - } - -#if defined(OS_WIN) - NaClBrokerService::GetInstance()->OnLoaderDied(); -#endif - BrowserChildProcessHost::OnChildDied(); -} - // This only ever runs on the BrowserThread::FILE thread. // If multiple tasks are posted, the later ones are no-ops. void NaClBrowser::OpenIrtLibraryFile() { @@ -519,7 +519,3 @@ bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) { NOTREACHED() << "Invalid message with type = " << msg.type(); return false; } - -bool NaClProcessHost::CanShutdown() { - return true; -} diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h index 1ccb0f8..c2d8d8f 100644 --- a/chrome/browser/nacl_host/nacl_process_host.h +++ b/chrome/browser/nacl_host/nacl_process_host.h @@ -43,7 +43,6 @@ class NaClProcessHost : public BrowserChildProcessHost { protected: virtual base::TerminationStatus GetChildTerminationStatus( int* exit_code) OVERRIDE; - virtual void OnChildDied() OVERRIDE; private: // Internal class that holds the nacl::Handle objecs so that @@ -59,8 +58,6 @@ class NaClProcessHost : public BrowserChildProcessHost { void IrtReady(); void SendStart(base::PlatformFile irt_file); - virtual bool CanShutdown() OVERRIDE; - private: // The ChromeRenderMessageFilter that requested this NaCl process. We use // this for sending the reply once the process has started. diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 854a235..f8d1793 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -604,8 +604,6 @@ 'sources': [ 'service/chrome_service_application_mac.h', 'service/chrome_service_application_mac.mm', - 'service/service_child_process_host.cc', - 'service/service_child_process_host.h', 'service/service_ipc_server.cc', 'service/service_ipc_server.h', 'service/service_main.cc', diff --git a/chrome/service/service_child_process_host.cc b/chrome/service/service_child_process_host.cc deleted file mode 100644 index 234b899..0000000 --- a/chrome/service/service_child_process_host.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/service/service_child_process_host.h" - -#include "base/command_line.h" -#include "base/logging.h" -#include "base/process_util.h" -#include "chrome/common/chrome_switches.h" -#include "content/public/common/result_codes.h" - -#if defined(OS_WIN) -#include "base/file_path.h" -#include "content/common/sandbox_policy.h" -#endif // defined(OS_WIN) - -ServiceChildProcessHost::ServiceChildProcessHost() - : handle_(base::kNullProcessHandle) { -} - -ServiceChildProcessHost::~ServiceChildProcessHost() { - // We need to kill the child process when the host dies. - base::KillProcess(handle_, content::RESULT_CODE_NORMAL_EXIT, false); -} - -bool ServiceChildProcessHost::Launch(CommandLine* cmd_line, - bool no_sandbox, - const FilePath& exposed_dir) { -#if !defined(OS_WIN) - // TODO(sanjeevr): Implement for non-Windows OSes. - NOTIMPLEMENTED(); - return false; -#else // !defined(OS_WIN) - - if (no_sandbox) { - base::ProcessHandle process = base::kNullProcessHandle; - cmd_line->AppendSwitch(switches::kNoSandbox); - base::LaunchProcess(*cmd_line, base::LaunchOptions(), &handle_); - } else { - handle_ = sandbox::StartProcessWithAccess(cmd_line, exposed_dir); - } - return (handle_ != base::kNullProcessHandle); -#endif // !defined(OS_WIN) -} diff --git a/chrome/service/service_child_process_host.h b/chrome/service/service_child_process_host.h deleted file mode 100644 index 44337be..0000000 --- a/chrome/service/service_child_process_host.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_SERVICE_SERVICE_CHILD_PROCESS_HOST_H_ -#define CHROME_SERVICE_SERVICE_CHILD_PROCESS_HOST_H_ -#pragma once - -#include "base/process.h" -#include "content/common/child_process_host.h" - -class CommandLine; - -// Plugins/workers and other child processes that live on the IO thread should -// derive from this class. -// -class ServiceChildProcessHost : public ChildProcessHost { - public: - virtual ~ServiceChildProcessHost(); - - protected: - ServiceChildProcessHost(); - - // Derived classes call this to launch the child process synchronously. - // TODO(sanjeevr): Determine whether we need to make the launch asynchronous. - // |exposed_dir| is the path to tbe exposed to the sandbox. This is ignored - // if |no_sandbox| is true. - bool Launch(CommandLine* cmd_line, - bool no_sandbox, - const FilePath& exposed_dir); - - base::ProcessHandle handle() const { return handle_; } - - private: - base::ProcessHandle handle_; - - DISALLOW_COPY_AND_ASSIGN(ServiceChildProcessHost); -}; - -#endif // CHROME_SERVICE_SERVICE_CHILD_PROCESS_HOST_H_ diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc index 8352526..d82007a 100644 --- a/chrome/service/service_utility_process_host.cc +++ b/chrome/service/service_utility_process_host.cc @@ -7,31 +7,41 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/file_util.h" +#include "base/logging.h" #include "base/message_loop.h" #include "base/message_loop_proxy.h" +#include "base/process_util.h" #include "base/scoped_temp_dir.h" #include "base/utf_string_conversions.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_utility_messages.h" +#include "content/common/child_process_host.h" +#include "content/public/common/result_codes.h" #include "ipc/ipc_switches.h" #include "printing/page_range.h" #include "ui/base/ui_base_switches.h" #include "ui/gfx/rect.h" #if defined(OS_WIN) +#include "base/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/win/scoped_handle.h" +#include "content/common/sandbox_policy.h" #include "printing/emf_win.h" #endif ServiceUtilityProcessHost::ServiceUtilityProcessHost( Client* client, base::MessageLoopProxy* client_message_loop_proxy) - : client_(client), + : handle_(base::kNullProcessHandle), + client_(client), client_message_loop_proxy_(client_message_loop_proxy), waiting_for_reply_(false) { + child_process_host_.reset(new ChildProcessHost(this)); } ServiceUtilityProcessHost::~ServiceUtilityProcessHost() { + // We need to kill the child process when the host dies. + base::KillProcess(handle_, content::RESULT_CODE_NORMAL_EXIT, false); } bool ServiceUtilityProcessHost::StartRenderPDFPagesToMetafile( @@ -72,7 +82,7 @@ bool ServiceUtilityProcessHost::StartRenderPDFPagesToMetafile( if (!pdf_file_in_utility_process) return false; waiting_for_reply_ = true; - return Send( + return child_process_host_->Send( new ChromeUtilityMsg_RenderPDFPagesToMetafile( pdf_file_in_utility_process, metafile_path_, @@ -87,12 +97,13 @@ bool ServiceUtilityProcessHost::StartGetPrinterCapsAndDefaults( if (!StartProcess(true, exposed_path)) return false; waiting_for_reply_ = true; - return Send(new ChromeUtilityMsg_GetPrinterCapsAndDefaults(printer_name)); + return child_process_host_->Send( + new ChromeUtilityMsg_GetPrinterCapsAndDefaults(printer_name)); } bool ServiceUtilityProcessHost::StartProcess(bool no_sandbox, const FilePath& exposed_dir) { - if (!CreateChannel()) + if (!child_process_host_->CreateChannel()) return false; FilePath exe_path = GetUtilityProcessCmd(); @@ -103,34 +114,57 @@ bool ServiceUtilityProcessHost::StartProcess(bool no_sandbox, CommandLine cmd_line(exe_path); cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kUtilityProcess); - cmd_line.AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line.AppendSwitchASCII(switches::kProcessChannelID, + child_process_host_->channel_id()); cmd_line.AppendSwitch(switches::kLang); return Launch(&cmd_line, no_sandbox, exposed_dir); } +bool ServiceUtilityProcessHost::Launch(CommandLine* cmd_line, + bool no_sandbox, + const FilePath& exposed_dir) { +#if !defined(OS_WIN) + // TODO(sanjeevr): Implement for non-Windows OSes. + NOTIMPLEMENTED(); + return false; +#else // !defined(OS_WIN) + + if (no_sandbox) { + base::ProcessHandle process = base::kNullProcessHandle; + cmd_line->AppendSwitch(switches::kNoSandbox); + base::LaunchProcess(*cmd_line, base::LaunchOptions(), &handle_); + } else { + handle_ = sandbox::StartProcessWithAccess(cmd_line, exposed_dir); + } + return (handle_ != base::kNullProcessHandle); +#endif // !defined(OS_WIN) +} + FilePath ServiceUtilityProcessHost::GetUtilityProcessCmd() { #if defined(OS_LINUX) - int flags = CHILD_ALLOW_SELF; + int flags = ChildProcessHost::CHILD_ALLOW_SELF; #else - int flags = CHILD_NORMAL; + int flags = ChildProcessHost::CHILD_NORMAL; #endif - return GetChildPath(flags); + return ChildProcessHost::GetChildPath(flags); } bool ServiceUtilityProcessHost::CanShutdown() { return true; } -void ServiceUtilityProcessHost::OnChildDied() { +void ServiceUtilityProcessHost::OnChildDisconnected() { if (waiting_for_reply_) { // If we are yet to receive a reply then notify the client that the // child died. client_message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&Client::OnChildDied, client_.get())); } - // The base class implementation will delete |this|. - ServiceChildProcessHost::OnChildDied(); + delete this; +} + +void ServiceUtilityProcessHost::ShutdownStarted() { } bool ServiceUtilityProcessHost::OnMessageReceived(const IPC::Message& message) { diff --git a/chrome/service/service_utility_process_host.h b/chrome/service/service_utility_process_host.h index 49e2450..77cb2f7 100644 --- a/chrome/service/service_utility_process_host.h +++ b/chrome/service/service_utility_process_host.h @@ -14,11 +14,15 @@ #include "base/basictypes.h" #include "base/file_path.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/process.h" #include "base/task.h" #include "ipc/ipc_channel.h" -#include "chrome/service/service_child_process_host.h" +#include "content/public/common/child_process_host_delegate.h" #include "printing/pdf_render_settings.h" +class ChildProcessHost; +class CommandLine; class ScopedTempDir; namespace base { @@ -34,7 +38,7 @@ struct PrinterCapsAndDefaults; // Acts as the service-side host to a utility child process. A // utility process is a short-lived sandboxed process that is created to run // a specific task. -class ServiceUtilityProcessHost : public ServiceChildProcessHost { +class ServiceUtilityProcessHost : public content::ChildProcessHostDelegate { public: // Consumers of ServiceUtilityProcessHost must implement this interface to // get results back. All functions are called on the thread passed along @@ -101,9 +105,11 @@ class ServiceUtilityProcessHost : public ServiceChildProcessHost { // Allows this method to be overridden for tests. virtual FilePath GetUtilityProcessCmd(); - // ChildProcessHost implementation. + // ChildProcessHostDelegate implementation: virtual bool CanShutdown() OVERRIDE; - virtual void OnChildDied() OVERRIDE; + virtual void OnChildDisconnected() OVERRIDE; + virtual void ShutdownStarted() OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; private: // Starts a process. Returns true iff it succeeded. |exposed_dir| is the @@ -111,22 +117,26 @@ class ServiceUtilityProcessHost : public ServiceChildProcessHost { // true. bool StartProcess(bool no_sandbox, const FilePath& exposed_dir); - // IPC messages: - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - // Called when at least one page in the specified PDF has been rendered - // successfully into metafile_path_; + // Launch the child process synchronously. + // TODO(sanjeevr): Determine whether we need to make the launch asynchronous. + // |exposed_dir| is the path to tbe exposed to the sandbox. This is ignored + // if |no_sandbox| is true. + bool Launch(CommandLine* cmd_line, + bool no_sandbox, + const FilePath& exposed_dir); + + base::ProcessHandle handle() const { return handle_; } + + // Messages handlers: void OnRenderPDFPagesToMetafileSucceeded(int highest_rendered_page_number); - // Called when PDF rendering failed. void OnRenderPDFPagesToMetafileFailed(); - // Called when the printer capabilities and defaults have been - // retrieved successfully. void OnGetPrinterCapsAndDefaultsSucceeded( const std::string& printer_name, const printing::PrinterCapsAndDefaults& caps_and_defaults); - // Called when the printer capabilities and defaults could not be - // retrieved successfully. void OnGetPrinterCapsAndDefaultsFailed(const std::string& printer_name); + scoped_ptr<ChildProcessHost> child_process_host_; + base::ProcessHandle handle_; // A pointer to our client interface, who will be informed of progress. scoped_refptr<Client> client_; scoped_refptr<base::MessageLoopProxy> client_message_loop_proxy_; diff --git a/content/browser/browser_child_process_host.cc b/content/browser/browser_child_process_host.cc index 508dade..3e56b6e 100644 --- a/content/browser/browser_child_process_host.cc +++ b/content/browser/browser_child_process_host.cc @@ -17,6 +17,7 @@ #include "content/browser/profiler_message_filter.h" #include "content/browser/renderer_host/resource_message_filter.h" #include "content/browser/trace_message_filter.h" +#include "content/common/child_process_host.h" #include "content/common/plugin_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" @@ -59,10 +60,11 @@ BrowserChildProcessHost::BrowserChildProcessHost( #endif disconnect_was_alive_(false) { data_.type = type; - data_.id = GenerateChildProcessUniqueId(); + data_.id = ChildProcessHost::GenerateChildProcessUniqueId(); - AddFilter(new TraceMessageFilter); - AddFilter(new ProfilerMessageFilter); + child_process_host_.reset(new ChildProcessHost(this)); + child_process_host_->AddFilter(new TraceMessageFilter); + child_process_host_->AddFilter(new ProfilerMessageFilter); g_child_process_list.Get().push_back(this); } @@ -96,7 +98,7 @@ void BrowserChildProcessHost::Launch( #elif defined(OS_POSIX) use_zygote, environ, - channel()->TakeClientFileDescriptor(), + child_process_host()->channel()->TakeClientFileDescriptor(), #endif cmd_line, &client_)); @@ -112,7 +114,7 @@ base::ProcessHandle BrowserChildProcessHost::GetChildProcessHandle() const { void BrowserChildProcessHost::ForceShutdown() { g_child_process_list.Get().remove(this); - ChildProcessHost::ForceShutdown(); + child_process_host_->ForceShutdown(); } void BrowserChildProcessHost::SetTerminateChildOnShutdown( @@ -132,11 +134,19 @@ base::TerminationStatus BrowserChildProcessHost::GetChildTerminationStatus( return child_process_->GetChildTerminationStatus(exit_code); } +bool BrowserChildProcessHost::OnMessageReceived(const IPC::Message& message) { + return false; +} + void BrowserChildProcessHost::OnChannelConnected(int32 peer_pid) { Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED); } -// The ChildProcessHost default implementation calls OnChildDied() always but at +bool BrowserChildProcessHost::CanShutdown() { + return true; +} + +// Normally a ChildProcessHostDelegate deletes itself from this callback, but at // this layer and below we need to have the final child process exit code to // properly bucket crashes vs kills. On Windows we can do this if we wait until // the process handle is signaled; on the rest of the platforms, we schedule a @@ -212,7 +222,7 @@ void BrowserChildProcessHost::OnChildDisconnected() { content::PROCESS_TYPE_MAX); // Notify in the main loop of the disconnection. Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); - OnChildDied(); + delete this; } // The child process handle has been signaled so the exit code is finally @@ -226,13 +236,17 @@ void BrowserChildProcessHost::OnWaitableEventSignaled( GetExitCodeProcess(waitable_event->Release(), &exit_code); delete waitable_event; if (exit_code == STILL_ACTIVE) { - OnChildDied(); + delete this; } else { BrowserChildProcessHost::OnChildDisconnected(); } #endif } +bool BrowserChildProcessHost::Send(IPC::Message* message) { + return child_process_host_->Send(message); +} + void BrowserChildProcessHost::ShutdownStarted() { // Must remove the process from the list now, in case it gets used for a // new instance before our watcher tells us that the process terminated. @@ -245,7 +259,7 @@ BrowserChildProcessHost::ClientHook::ClientHook(BrowserChildProcessHost* host) void BrowserChildProcessHost::ClientHook::OnProcessLaunched() { if (!host_->child_process_->GetHandle()) { - host_->OnChildDied(); + delete host_; return; } host_->data_.handle = host_->child_process_->GetHandle(); diff --git a/content/browser/browser_child_process_host.h b/content/browser/browser_child_process_host.h index a201c30..561d84e 100644 --- a/content/browser/browser_child_process_host.h +++ b/content/browser/browser_child_process_host.h @@ -8,13 +8,17 @@ #include <list> +#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/process.h" #include "base/synchronization/waitable_event_watcher.h" #include "content/browser/child_process_launcher.h" -#include "content/common/child_process_host.h" #include "content/common/content_export.h" #include "content/public/browser/child_process_data.h" +#include "content/public/common/child_process_host_delegate.h" +#include "ipc/ipc_message.h" + +class ChildProcessHost; namespace base { class WaitableEvent; @@ -26,9 +30,10 @@ class WaitableEvent; // [Browser]RenderProcessHost is the main exception that doesn't derive from // this class. That project lives on the UI thread. class CONTENT_EXPORT BrowserChildProcessHost : - public ChildProcessHost, + public content::ChildProcessHostDelegate, public ChildProcessLauncher::Client, - public base::WaitableEventWatcher::Delegate { + public base::WaitableEventWatcher::Delegate, + public IPC::Message::Sender { public: virtual ~BrowserChildProcessHost(); @@ -58,6 +63,9 @@ class CONTENT_EXPORT BrowserChildProcessHost : std::list<BrowserChildProcessHost*>::iterator iterator_; }; + // IPC::Message::Sender override + virtual bool Send(IPC::Message* message) OVERRIDE; + const content::ChildProcessData& data() const { return data_; } content::ProcessType type() const { return data_.type; } const string16& name() const { return data_.name; } @@ -102,13 +110,15 @@ class CONTENT_EXPORT BrowserChildProcessHost : // GetExitCodeProcess()). |exit_code| may be NULL. virtual base::TerminationStatus GetChildTerminationStatus(int* exit_code); - // Overrides from ChildProcessHost - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; + // ChildProcessHostDelegate implementation: + virtual bool CanShutdown() OVERRIDE; virtual void OnChildDisconnected() OVERRIDE; virtual void ShutdownStarted() OVERRIDE; - // Extends the base class implementation and removes this host from - // the host list. Calls ChildProcessHost::ForceShutdown - virtual void ForceShutdown() OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; + + // Removes this host from the host list. Calls ChildProcessHost::ForceShutdown + void ForceShutdown(); // Controls whether the child process should be terminated on browser // shutdown. Default is to always terminate. @@ -117,6 +127,9 @@ class CONTENT_EXPORT BrowserChildProcessHost : // Sends the given notification on the UI thread. void Notify(int type); + ChildProcessHost* child_process_host() const { + return child_process_host_.get(); + } void set_name(const string16& name) { data_.name = name; } void set_handle(base::ProcessHandle handle) { data_.handle = handle; } @@ -133,6 +146,7 @@ class CONTENT_EXPORT BrowserChildProcessHost : }; content::ChildProcessData data_; + scoped_ptr<ChildProcessHost> child_process_host_; ClientHook client_; scoped_ptr<ChildProcessLauncher> child_process_; diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index cdaac3e..3b18d38 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -17,6 +17,7 @@ #include "content/browser/gpu/gpu_process_host_ui_shim.h" #include "content/browser/renderer_host/render_widget_host.h" #include "content/browser/renderer_host/render_widget_host_view.h" +#include "content/common/child_process_host.h" #include "content/common/gpu/gpu_messages.h" #include "content/gpu/gpu_child_thread.h" #include "content/gpu/gpu_process.h" @@ -279,6 +280,25 @@ GpuProcessHost::GpuProcessHost(int host_id) GpuProcessHost::~GpuProcessHost() { DCHECK(CalledOnValidThread()); + + SendOutstandingReplies(); + UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", + DIED_FIRST_TIME + g_gpu_crash_count, + GPU_PROCESS_LIFETIME_EVENT_MAX); + + int exit_code; + base::TerminationStatus status = GetChildTerminationStatus(&exit_code); + UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus", + status, + base::TERMINATION_STATUS_MAX_ENUM); + + if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION || + status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { + UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessExitCode", + exit_code, + content::RESULT_CODE_LAST_CODE); + } + #if defined(OS_WIN) if (gpu_process_) CloseHandle(gpu_process_); @@ -299,14 +319,15 @@ GpuProcessHost::~GpuProcessHost() { } bool GpuProcessHost::Init() { - if (!CreateChannel()) + if (!child_process_host()->CreateChannel()) return false; if (in_process_) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kDisableGpuWatchdog); - in_process_gpu_thread_.reset(new GpuMainThread(channel_id())); + in_process_gpu_thread_.reset(new GpuMainThread( + child_process_host()->channel_id())); base::Thread::Options options; #if defined(OS_WIN) @@ -337,7 +358,7 @@ void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) { bool GpuProcessHost::Send(IPC::Message* msg) { DCHECK(CalledOnValidThread()); - if (opening_channel()) { + if (child_process_host()->opening_channel()) { queued_messages_.push(msg); return true; } @@ -488,10 +509,6 @@ void GpuProcessHost::OnGraphicsInfoCollected(const content::GPUInfo& gpu_info) { GpuDataManager::GetInstance()->UpdateGpuInfo(gpu_info); } -bool GpuProcessHost::CanShutdown() { - return true; -} - void GpuProcessHost::OnProcessLaunched() { // Send the GPU process handle to the UI thread before it has to // respond to any requests to establish a GPU channel. The response @@ -513,30 +530,6 @@ void GpuProcessHost::OnProcessLaunched() { #endif } -void GpuProcessHost::OnChildDied() { - SendOutstandingReplies(); - // Located in OnChildDied because OnProcessCrashed suffers from a race - // condition on Linux. - UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", - DIED_FIRST_TIME + g_gpu_crash_count, - GPU_PROCESS_LIFETIME_EVENT_MAX); - - int exit_code; - base::TerminationStatus status = GetChildTerminationStatus(&exit_code); - UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus", - status, - base::TERMINATION_STATUS_MAX_ENUM); - - if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION || - status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { - UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessExitCode", - exit_code, - content::RESULT_CODE_LAST_CODE); - } - - ChildProcessHost::OnChildDied(); -} - void GpuProcessHost::OnProcessCrashed(int exit_code) { SendOutstandingReplies(); if (++g_gpu_crash_count >= kGpuMaxCrashCount) { @@ -575,7 +568,8 @@ bool GpuProcessHost::LaunchGpuProcess() { CommandLine* cmd_line = new CommandLine(exe_path); cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess); - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, + child_process_host()->channel_id()); // Propagate relevant command line switches. static const char* const kSwitchNames[] = { diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h index e6ba2c0..073e8fd 100644 --- a/content/browser/gpu/gpu_process_host.h +++ b/content/browser/gpu/gpu_process_host.h @@ -92,9 +92,7 @@ class GpuProcessHost : public BrowserChildProcessHost, // Post an IPC message to the UI shim's message handler on the UI thread. void RouteOnUIThread(const IPC::Message& message); - virtual bool CanShutdown() OVERRIDE; virtual void OnProcessLaunched() OVERRIDE; - virtual void OnChildDied() OVERRIDE; virtual void OnProcessCrashed(int exit_code) OVERRIDE; // Message handlers. diff --git a/content/browser/plugin_data_remover_impl.cc b/content/browser/plugin_data_remover_impl.cc index da0dbfc..38489d5 100644 --- a/content/browser/plugin_data_remover_impl.cc +++ b/content/browser/plugin_data_remover_impl.cc @@ -10,6 +10,7 @@ #include "base/version.h" #include "content/browser/plugin_process_host.h" #include "content/browser/plugin_service.h" +#include "content/common/child_process_host.h" #include "content/common/plugin_messages.h" #include "content/public/browser/browser_thread.h" #include "webkit/plugins/npapi/plugin_group.h" diff --git a/content/browser/plugin_loader_posix.cc b/content/browser/plugin_loader_posix.cc index 6d2be85..bc96427 100644 --- a/content/browser/plugin_loader_posix.cc +++ b/content/browser/plugin_loader_posix.cc @@ -8,6 +8,7 @@ #include "base/message_loop.h" #include "base/message_loop_proxy.h" #include "base/metrics/histogram.h" +#include "content/common/child_process_host.h" #include "content/common/utility_messages.h" #include "content/public/browser/browser_thread.h" #include "webkit/plugins/npapi/plugin_list.h" diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc index 91c22c4..293072d 100644 --- a/content/browser/plugin_process_host.cc +++ b/content/browser/plugin_process_host.cc @@ -22,6 +22,7 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "content/browser/plugin_service.h" +#include "content/common/child_process_host.h" #include "content/common/plugin_messages.h" #include "content/common/resource_messages.h" #include "content/public/browser/browser_thread.h" @@ -167,7 +168,7 @@ bool PluginProcessHost::Init(const webkit::WebPluginInfo& info, info_ = info; set_name(info_.name); - if (!CreateChannel()) + if (!child_process_host()->CreateChannel()) return false; // Build command line for plugin. When we have a plugin launcher, we can't @@ -180,14 +181,15 @@ bool PluginProcessHost::Init(const webkit::WebPluginInfo& info, // Run the plug-in process in a mode tolerant of heap execution without // explicit mprotect calls. Some plug-ins still rely on this quaint and // archaic "feature." See http://crbug.com/93551. - int flags = CHILD_ALLOW_HEAP_EXECUTION; + int flags = ChildProcessHost::CHILD_ALLOW_HEAP_EXECUTION; #elif defined(OS_LINUX) - int flags = plugin_launcher.empty() ? CHILD_ALLOW_SELF : CHILD_NORMAL; + int flags = plugin_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF : + ChildProcessHost::CHILD_NORMAL; #else - int flags = CHILD_NORMAL; + int flags = ChildProcessHost::CHILD_NORMAL; #endif - FilePath exe_path = GetChildPath(flags); + FilePath exe_path = ChildProcessHost::GetChildPath(flags); if (exe_path.empty()) return false; @@ -233,7 +235,8 @@ bool PluginProcessHost::Init(const webkit::WebPluginInfo& info, cmd_line->AppendSwitchASCII(switches::kLang, locale); } - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, + child_process_host()->channel_id()); #if defined(OS_POSIX) base::environment_vector env; @@ -279,6 +282,10 @@ void PluginProcessHost::ForceShutdown() { BrowserChildProcessHost::ForceShutdown(); } +void PluginProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { + child_process_host()->AddFilter(filter); +} + bool PluginProcessHost::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PluginProcessHost, msg) @@ -359,7 +366,7 @@ void PluginProcessHost::CancelPendingRequestsForResourceContext( void PluginProcessHost::OpenChannelToPlugin(Client* client) { Notify(content::NOTIFICATION_CHILD_INSTANCE_CREATED); client->SetPluginInfo(info_); - if (opening_channel()) { + if (child_process_host()->opening_channel()) { // The channel is already in the process of being opened. Put // this "open channel" request into a queue of requests that will // be run once the channel is open. diff --git a/content/browser/plugin_process_host.h b/content/browser/plugin_process_host.h index b56183f..6ce5f08 100644 --- a/content/browser/plugin_process_host.h +++ b/content/browser/plugin_process_host.h @@ -17,6 +17,7 @@ #include "base/memory/ref_counted.h" #include "content/browser/browser_child_process_host.h" #include "content/common/content_export.h" +#include "ipc/ipc_channel_proxy.h" #include "webkit/plugins/webplugininfo.h" #include "ui/gfx/native_widget_types.h" @@ -69,7 +70,7 @@ class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHost { bool Init(const webkit::WebPluginInfo& info, const std::string& locale); // Force the plugin process to shutdown (cleanly). - virtual void ForceShutdown() OVERRIDE; + void ForceShutdown(); virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; @@ -109,6 +110,9 @@ class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHost { void AddWindow(HWND window); #endif + // Adds an IPC message filter. A reference will be kept to the filter. + void AddFilter(IPC::ChannelProxy::MessageFilter* filter); + private: // Sends a message to the plugin process to request creation of a new channel // for the given mime type. diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc index 8b5faef..f4ccd33 100644 --- a/content/browser/ppapi_plugin_process_host.cc +++ b/content/browser/ppapi_plugin_process_host.cc @@ -11,6 +11,7 @@ #include "base/utf_string_conversions.h" #include "content/browser/plugin_service.h" #include "content/browser/renderer_host/render_message_filter.h" +#include "content/common/child_process_host.h" #include "content/common/child_process_messages.h" #include "content/public/common/content_switches.h" #include "content/public/common/pepper_plugin_info.h" @@ -84,7 +85,7 @@ PpapiPluginProcessHost* PpapiPluginProcessHost::CreateBrokerHost( } void PpapiPluginProcessHost::OpenChannelToPlugin(Client* client) { - if (opening_channel()) { + if (child_process_host()->opening_channel()) { // The channel is already in the process of being opened. Put // this "open channel" request into a queue of requests that will // be run once the channel is open. @@ -102,7 +103,7 @@ PpapiPluginProcessHost::PpapiPluginProcessHost(net::HostResolver* host_resolver) network_observer_(new PluginNetworkObserver(this)), is_broker_(false), process_id_(ChildProcessHost::GenerateChildProcessUniqueId()) { - AddFilter(filter_.get()); + child_process_host()->AddFilter(filter_.get()); } PpapiPluginProcessHost::PpapiPluginProcessHost() @@ -119,7 +120,7 @@ bool PpapiPluginProcessHost::Init(const content::PepperPluginInfo& info) { set_name(UTF8ToUTF16(info.name)); } - if (!CreateChannel()) + if (!child_process_host()->CreateChannel()) return false; const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); @@ -140,7 +141,8 @@ bool PpapiPluginProcessHost::Init(const content::PepperPluginInfo& info) { cmd_line->AppendSwitchASCII(switches::kProcessType, is_broker_ ? switches::kPpapiBrokerProcess : switches::kPpapiPluginProcess); - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, + child_process_host()->channel_id()); // These switches are forwarded to both plugin and broker pocesses. static const char* kCommonForwardSwitches[] = { @@ -198,10 +200,6 @@ void PpapiPluginProcessHost::RequestPluginChannel(Client* client) { client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); } -bool PpapiPluginProcessHost::CanShutdown() { - return true; -} - void PpapiPluginProcessHost::OnProcessLaunched() { } diff --git a/content/browser/ppapi_plugin_process_host.h b/content/browser/ppapi_plugin_process_host.h index a968a27..f92aa1d 100644 --- a/content/browser/ppapi_plugin_process_host.h +++ b/content/browser/ppapi_plugin_process_host.h @@ -82,7 +82,6 @@ class PpapiPluginProcessHost void RequestPluginChannel(Client* client); - virtual bool CanShutdown() OVERRIDE; virtual void OnProcessLaunched() OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 267d1cc..f84b968 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -686,8 +686,7 @@ void RenderMessageFilter::OnCheckNotificationPermission( void RenderMessageFilter::OnAllocateSharedMemory( uint32 buffer_size, base::SharedMemoryHandle* handle) { - ChildProcessHost::OnAllocateSharedMemory( - buffer_size, peer_handle(), handle); + ChildProcessHost::AllocateSharedMemory(buffer_size, peer_handle(), handle); } net::URLRequestContext* RenderMessageFilter::GetRequestContextForURL( diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc index 65a7e70..8bc2234 100644 --- a/content/browser/utility_process_host.cc +++ b/content/browser/utility_process_host.cc @@ -9,6 +9,7 @@ #include "base/command_line.h" #include "base/message_loop.h" #include "base/utf_string_conversions.h" +#include "content/common/child_process_host.h" #include "content/common/utility_messages.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/content_switches.h" @@ -40,9 +41,9 @@ UtilityProcessHost::UtilityProcessHost(Client* client, is_batch_mode_(false), no_sandbox_(false), #if defined(OS_LINUX) - child_flags_(CHILD_ALLOW_SELF), + child_flags_(ChildProcessHost::CHILD_ALLOW_SELF), #else - child_flags_(CHILD_NORMAL), + child_flags_(ChildProcessHost::CHILD_NORMAL), #endif started_(false) { } @@ -72,7 +73,7 @@ void UtilityProcessHost::EndBatchMode() { } FilePath UtilityProcessHost::GetUtilityProcessCmd() { - return GetChildPath(child_flags_); + return ChildProcessHost::GetChildPath(child_flags_); } bool UtilityProcessHost::StartProcess() { @@ -86,7 +87,7 @@ bool UtilityProcessHost::StartProcess() { // launches a UtilityProcessHost. set_name(ASCIIToUTF16("utility process")); - if (!CreateChannel()) + if (!child_process_host()->CreateChannel()) return false; FilePath exe_path = GetUtilityProcessCmd(); @@ -98,7 +99,8 @@ bool UtilityProcessHost::StartProcess() { CommandLine* cmd_line = new CommandLine(exe_path); cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kUtilityProcess); - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, + child_process_host()->channel_id()); std::string locale = content::GetContentClient()->browser()->GetApplicationLocale(); cmd_line->AppendSwitchASCII(switches::kLang, locale); @@ -151,7 +153,3 @@ void UtilityProcessHost::OnProcessCrashed(int exit_code) { client_thread_id_, FROM_HERE, base::Bind(&Client::OnProcessCrashed, client_.get(), exit_code)); } - -bool UtilityProcessHost::CanShutdown() { - return true; -} diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h index de53610..b81d12d 100644 --- a/content/browser/utility_process_host.h +++ b/content/browser/utility_process_host.h @@ -84,7 +84,6 @@ class CONTENT_EXPORT UtilityProcessHost : public BrowserChildProcessHost { // BrowserChildProcessHost: virtual void OnProcessCrashed(int exit_code) OVERRIDE; - virtual bool CanShutdown() OVERRIDE; // A pointer to our client interface, who will be informed of progress. scoped_refptr<Client> client_; diff --git a/content/browser/worker_host/worker_process_host.cc b/content/browser/worker_host/worker_process_host.cc index ba29447..68d75c9 100644 --- a/content/browser/worker_host/worker_process_host.cc +++ b/content/browser/worker_host/worker_process_host.cc @@ -31,6 +31,7 @@ #include "content/browser/worker_host/message_port_service.h" #include "content/browser/worker_host/worker_message_filter.h" #include "content/browser/worker_host/worker_service.h" +#include "content/common/child_process_host.h" #include "content/common/debug_flags.h" #include "content/common/view_messages.h" #include "content/common/worker_messages.h" @@ -111,22 +112,23 @@ WorkerProcessHost::~WorkerProcessHost() { } bool WorkerProcessHost::Init(int render_process_id) { - if (!CreateChannel()) + if (!child_process_host()->CreateChannel()) return false; #if defined(OS_LINUX) - int flags = CHILD_ALLOW_SELF; + int flags = ChildProcessHost::CHILD_ALLOW_SELF; #else - int flags = CHILD_NORMAL; + int flags = ChildProcessHost::CHILD_NORMAL; #endif - FilePath exe_path = GetChildPath(flags); + FilePath exe_path = ChildProcessHost::GetChildPath(flags); if (exe_path.empty()) return false; CommandLine* cmd_line = new CommandLine(exe_path); cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kWorkerProcess); - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, + child_process_host()->channel_id()); std::string locale = content::GetContentClient()->browser()->GetApplicationLocale(); cmd_line->AppendSwitchASCII(switches::kLang, locale); @@ -237,29 +239,30 @@ void WorkerProcessHost::CreateMessageFilters(int render_process_id) { id(), content::PROCESS_TYPE_WORKER, resource_context_, new URLRequestContextSelector(request_context), resource_dispatcher_host_); - AddFilter(resource_message_filter); + child_process_host()->AddFilter(resource_message_filter); worker_message_filter_ = new WorkerMessageFilter( render_process_id, resource_context_, resource_dispatcher_host_, base::Bind(&WorkerService::next_worker_route_id, base::Unretained(WorkerService::GetInstance()))); - AddFilter(worker_message_filter_); - AddFilter(new AppCacheDispatcherHost( + child_process_host()->AddFilter(worker_message_filter_); + child_process_host()->AddFilter(new AppCacheDispatcherHost( resource_context_->appcache_service(), id())); - AddFilter(new FileSystemDispatcherHost( + child_process_host()->AddFilter(new FileSystemDispatcherHost( request_context, resource_context_->file_system_context())); - AddFilter(new FileUtilitiesMessageFilter(id())); - AddFilter(new BlobMessageFilter( + child_process_host()->AddFilter(new FileUtilitiesMessageFilter(id())); + child_process_host()->AddFilter(new BlobMessageFilter( id(), resource_context_->blob_storage_context())); - AddFilter(new MimeRegistryMessageFilter()); - AddFilter(new DatabaseMessageFilter( + child_process_host()->AddFilter(new MimeRegistryMessageFilter()); + child_process_host()->AddFilter(new DatabaseMessageFilter( resource_context_->database_tracker())); SocketStreamDispatcherHost* socket_stream_dispatcher_host = new SocketStreamDispatcherHost( new URLRequestContextSelector(request_context), resource_context_); - AddFilter(socket_stream_dispatcher_host); - AddFilter(new content::WorkerDevToolsMessageFilter(id())); + child_process_host()->AddFilter(socket_stream_dispatcher_host); + child_process_host()->AddFilter( + new content::WorkerDevToolsMessageFilter(id())); } void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) { diff --git a/content/common/child_process_host.cc b/content/common/child_process_host.cc index fd1de4a..002e016 100644 --- a/content/common/child_process_host.cc +++ b/content/common/child_process_host.cc @@ -17,6 +17,7 @@ #include "base/stringprintf.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "content/common/child_process_messages.h" +#include "content/public/common/child_process_host_delegate.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "ipc/ipc_logging.h" @@ -73,8 +74,9 @@ FilePath TransformPathForFeature(const FilePath& path, } // namespace #endif // OS_MACOSX -ChildProcessHost::ChildProcessHost() - : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), +ChildProcessHost::ChildProcessHost(content::ChildProcessHostDelegate* delegate) + : delegate_(delegate), + peer_handle_(base::kNullProcessHandle), opening_channel_(false) { #if defined(OS_WIN) AddFilter(new FontCacheDispatcher()); @@ -86,7 +88,8 @@ ChildProcessHost::~ChildProcessHost() { filters_[i]->OnChannelClosing(); filters_[i]->OnFilterRemoved(); } - listener_.Shutdown(); + + base::CloseProcessHandle(peer_handle_); } void ChildProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { @@ -147,7 +150,7 @@ void ChildProcessHost::ForceShutdown() { bool ChildProcessHost::CreateChannel() { channel_id_ = GenerateRandomChannelID(this); channel_.reset(new IPC::Channel( - channel_id_, IPC::Channel::MODE_SERVER, &listener_)); + channel_id_, IPC::Channel::MODE_SERVER, this)); if (!channel_->Connect()) return false; @@ -167,16 +170,6 @@ bool ChildProcessHost::CreateChannel() { return true; } -bool ChildProcessHost::OnMessageReceived(const IPC::Message& msg) { - return false; -} - -void ChildProcessHost::OnChannelConnected(int32 peer_pid) { -} - -void ChildProcessHost::OnChannelError() { -} - bool ChildProcessHost::Send(IPC::Message* message) { if (!channel_.get()) { delete message; @@ -185,7 +178,7 @@ bool ChildProcessHost::Send(IPC::Message* message) { return channel_->Send(message); } -void ChildProcessHost::OnAllocateSharedMemory( +void ChildProcessHost::AllocateSharedMemory( uint32 buffer_size, base::ProcessHandle child_process_handle, base::SharedMemoryHandle* shared_memory_handle) { base::SharedMemory shared_buf; @@ -215,35 +208,7 @@ int ChildProcessHost::GenerateChildProcessUniqueId() { return base::subtle::NoBarrier_AtomicIncrement(&last_unique_child_id, 1); } - -void ChildProcessHost::OnChildDied() { - delete this; -} - -void ChildProcessHost::OnChildDisconnected() { - OnChildDied(); -} - -void ChildProcessHost::ShutdownStarted() { -} - -ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) - : host_(host), peer_handle_(base::kNullProcessHandle) { -} - -ChildProcessHost::ListenerHook::~ListenerHook() { - base::CloseProcessHandle(peer_handle_); -} - -void ChildProcessHost::ListenerHook::Shutdown() { - host_ = NULL; -} - -bool ChildProcessHost::ListenerHook::OnMessageReceived( - const IPC::Message& msg) { - if (!host_) - return true; - +bool ChildProcessHost::OnMessageReceived(const IPC::Message& msg) { #ifdef IPC_MESSAGE_LOG_ENABLED IPC::Logging* logger = IPC::Logging::GetInstance(); if (msg.type() == IPC_LOGGING_ID) { @@ -256,72 +221,62 @@ bool ChildProcessHost::ListenerHook::OnMessageReceived( #endif bool handled = false; - for (size_t i = 0; i < host_->filters_.size(); ++i) { - if (host_->filters_[i]->OnMessageReceived(msg)) { + for (size_t i = 0; i < filters_.size(); ++i) { + if (filters_[i]->OnMessageReceived(msg)) { handled = true; break; } } if (!handled) { - bool msg_is_good = false; handled = true; - IPC_BEGIN_MESSAGE_MAP_EX(ListenerHook, msg, msg_is_good) + IPC_BEGIN_MESSAGE_MAP(ChildProcessHost, msg) IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest, OnShutdownRequest) IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory, OnAllocateSharedMemory) IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP_EX() + IPC_END_MESSAGE_MAP() if (!handled) - handled = host_->OnMessageReceived(msg); + handled = delegate_->OnMessageReceived(msg); } #ifdef IPC_MESSAGE_LOG_ENABLED if (logger->Enabled()) - logger->OnPostDispatchMessage(msg, host_->channel_id_); + logger->OnPostDispatchMessage(msg, channel_id_); #endif return handled; } -void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { - if (!host_) - return; +void ChildProcessHost::OnChannelConnected(int32 peer_pid) { if (!base::OpenProcessHandle(peer_pid, &peer_handle_)) { NOTREACHED(); } - host_->opening_channel_ = false; - host_->OnChannelConnected(peer_pid); - for (size_t i = 0; i < host_->filters_.size(); ++i) - host_->filters_[i]->OnChannelConnected(peer_pid); + opening_channel_ = false; + delegate_->OnChannelConnected(peer_pid); + for (size_t i = 0; i < filters_.size(); ++i) + filters_[i]->OnChannelConnected(peer_pid); } -void ChildProcessHost::ListenerHook::OnChannelError() { - if (!host_) - return; - host_->opening_channel_ = false; - host_->OnChannelError(); +void ChildProcessHost::OnChannelError() { + opening_channel_ = false; + delegate_->OnChannelError(); - for (size_t i = 0; i < host_->filters_.size(); ++i) - host_->filters_[i]->OnChannelError(); + for (size_t i = 0; i < filters_.size(); ++i) + filters_[i]->OnChannelError(); // This will delete host_, which will also destroy this! - host_->OnChildDisconnected(); -} - -bool ChildProcessHost::ListenerHook::Send(IPC::Message* message) { - return host_->Send(message); + delegate_->OnChildDisconnected(); } -void ChildProcessHost::ListenerHook::OnAllocateSharedMemory( +void ChildProcessHost::OnAllocateSharedMemory( uint32 buffer_size, base::SharedMemoryHandle* handle) { - ChildProcessHost::OnAllocateSharedMemory( - buffer_size, peer_handle_, handle); + AllocateSharedMemory(buffer_size, peer_handle_, handle); } -void ChildProcessHost::ListenerHook::OnShutdownRequest() { - if (host_->CanShutdown()) - host_->Send(new ChildProcessMsg_Shutdown()); +void ChildProcessHost::OnShutdownRequest() { + if (delegate_->CanShutdown()) + Send(new ChildProcessMsg_Shutdown()); } diff --git a/content/common/child_process_host.h b/content/common/child_process_host.h index be73fa1..7f044f4 100644 --- a/content/common/child_process_host.h +++ b/content/common/child_process_host.h @@ -21,12 +21,12 @@ class FilePath; -namespace IPC { -class Message; +namespace content { +class ChildProcessHostDelegate; } // Provides common functionality for hosting a child process and processing IPC -// messages between the host and the child process. Subclasses are responsible +// messages between the host and the child process. Users are responsible // for the actual launching and terminating of the child processes. class CONTENT_EXPORT ChildProcessHost : public IPC::Channel::Listener, public IPC::Message::Sender { @@ -80,6 +80,8 @@ class CONTENT_EXPORT ChildProcessHost : public IPC::Channel::Listener, // On failure, returns an empty FilePath. static FilePath GetChildPath(int flags); + explicit ChildProcessHost(content::ChildProcessHostDelegate* delegate); + // IPC::Message::Sender implementation. virtual bool Send(IPC::Message* message) OVERRIDE; @@ -87,7 +89,7 @@ class CONTENT_EXPORT ChildProcessHost : public IPC::Channel::Listener, void AddFilter(IPC::ChannelProxy::MessageFilter* filter); // Public and static for reuse by RenderMessageFilter. - static void OnAllocateSharedMemory( + static void AllocateSharedMemory( uint32 buffer_size, base::ProcessHandle child_process, base::SharedMemoryHandle* handle); @@ -104,68 +106,30 @@ class CONTENT_EXPORT ChildProcessHost : public IPC::Channel::Listener, // but normally this will be used on the IO thread. static int GenerateChildProcessUniqueId(); - protected: - ChildProcessHost(); - - // Derived classes return true if it's ok to shut down the child process. - virtual bool CanShutdown() = 0; - // Send the shutdown message to the child process. // Does not check if CanShutdown is true. - virtual void ForceShutdown(); + void ForceShutdown(); // Creates the IPC channel. Returns true iff it succeeded. - virtual bool CreateChannel(); - - // IPC::Channel::Listener implementation: - virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; - virtual void OnChannelError() OVERRIDE; + bool CreateChannel(); bool opening_channel() { return opening_channel_; } const std::string& channel_id() { return channel_id_; } IPC::Channel* channel() { return channel_.get(); } - // Called when the child process goes away. See OnChildDisconnected(). - virtual void OnChildDied(); - - // Called when the child process unexpected closes the IPC channel. The - // default action is to call OnChildDied(). Subclasses might want to override - // this behavior. - virtual void OnChildDisconnected(); - - // Notifies the derived class that we told the child process to kill itself. - virtual void ShutdownStarted(); - private: - // 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 { - public: - explicit ListenerHook(ChildProcessHost* host); - virtual ~ListenerHook(); - - void Shutdown(); - - // IPC::Channel::Listener methods: - virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; - virtual void OnChannelError() OVERRIDE; - - bool Send(IPC::Message* message); - - private: - void OnShutdownRequest(); - void OnAllocateSharedMemory(uint32 buffer_size, - base::SharedMemoryHandle* handle); - ChildProcessHost* host_; - base::ProcessHandle peer_handle_; - DISALLOW_COPY_AND_ASSIGN(ListenerHook); - }; + // IPC::Channel::Listener methods: + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; + virtual void OnChannelError() OVERRIDE; - ListenerHook listener_; + // Message handlers: + void OnShutdownRequest(); + void OnAllocateSharedMemory(uint32 buffer_size, + base::SharedMemoryHandle* handle); + content::ChildProcessHostDelegate* delegate_; + base::ProcessHandle peer_handle_; bool opening_channel_; // True while we're waiting the channel to be opened. scoped_ptr<IPC::Channel> channel_; std::string channel_id_; diff --git a/content/content_common.gypi b/content/content_common.gypi index b4891f8..a9bdb55 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -29,6 +29,7 @@ ], 'sources': [ 'public/common/bindings_policy.h', + 'public/common/child_process_host_delegate.h', 'public/common/child_process_sandbox_support_linux.h', 'public/common/content_constants.cc', 'public/common/content_constants.h', diff --git a/content/public/common/child_process_host_delegate.h b/content/public/common/child_process_host_delegate.h new file mode 100644 index 0000000..7b9cbd1 --- /dev/null +++ b/content/public/common/child_process_host_delegate.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PULIC_COMMON_CHILD_PROCESS_HOST_DELEGATE_H_ +#define CONTENT_PULIC_COMMON_CHILD_PROCESS_HOST_DELEGATE_H_ +#pragma once + +#include <string> + +#include "ipc/ipc_channel.h" + +namespace content { + +// Interface that all users of ChildProcessHost need to provide. +class ChildProcessHostDelegate : public IPC::Channel::Listener { + public: + virtual ~ChildProcessHostDelegate() {} + + // Derived classes return true if it's ok to shut down the child process. + // Normally they would return true. The exception is if the host is in the + // middle of sending a request to the process, in which case the other side + // might think it's ok to shutdown, when really it's not. + virtual bool CanShutdown() = 0; + + // Notifies the derived class that we told the child process to kill itself. + virtual void ShutdownStarted() = 0; + + // Called when the child process unexpected closes the IPC channel. Delegates + // would normally delete the object in this case. + virtual void OnChildDisconnected() = 0; +}; + +}; // namespace content + +#endif // CONTENT_PULIC_COMMON_CHILD_PROCESS_HOST_DELEGATE_H_ |