Index: chrome/browser/renderer_host/browser_render_process_host.cc |
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc |
index cb43eb99c4163d2678f159b675ef3a021727c03e..6c9ab932b51b96d4b1cd9833b1d17848f827c8b4 100644 |
--- a/chrome/browser/renderer_host/browser_render_process_host.cc |
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc |
@@ -2,8 +2,13 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+// Represents the browser side of the browser <--> renderer communication |
+// channel. There will be one RenderProcessHost per renderer process. |
+ |
#include "chrome/browser/renderer_host/browser_render_process_host.h" |
+#include "build/build_config.h" |
+ |
#include <algorithm> |
#include <sstream> |
#include <vector> |
@@ -18,22 +23,17 @@ |
#include "base/singleton.h" |
#include "base/string_util.h" |
#include "base/thread.h" |
-#include "base/win_util.h" |
#include "chrome/app/result_codes.h" |
-#include "chrome/browser/browser.h" |
#include "chrome/browser/browser_process.h" |
#include "chrome/browser/cache_manager_host.h" |
#include "chrome/browser/extensions/user_script_master.h" |
#include "chrome/browser/history/history.h" |
#include "chrome/browser/plugin_service.h" |
#include "chrome/browser/render_widget_helper.h" |
-#include "chrome/browser/render_view_host.h" |
#include "chrome/browser/renderer_security_policy.h" |
#include "chrome/browser/resource_message_filter.h" |
-#include "chrome/browser/sandbox_policy.h" |
#include "chrome/browser/spellchecker.h" |
#include "chrome/browser/visitedlink_master.h" |
-#include "chrome/browser/tab_contents/web_contents.h" |
#include "chrome/common/chrome_paths.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/debug_flags.h" |
@@ -42,11 +42,21 @@ |
#include "chrome/common/pref_names.h" |
#include "chrome/common/pref_service.h" |
#include "chrome/common/process_watcher.h" |
-#include "chrome/common/win_util.h" |
#include "chrome/renderer/render_process.h" |
#include "net/base/cookie_monster.h" |
#include "net/base/net_util.h" |
+ |
+#if defined(OS_WIN) |
+// TODO(port): see comment by the only usage of RenderViewHost in this file. |
+#include "chrome/browser/render_view_host.h" |
+ |
+// Once the above TODO is finished, then this block is all Windows-specific |
+// files. |
+#include "base/win_util.h" |
+#include "chrome/browser/sandbox_policy.h" |
+#include "chrome/common/win_util.h" |
#include "sandbox/src/sandbox.h" |
+#endif |
#include "SkBitmap.h" |
@@ -65,7 +75,9 @@ class RendererMainThread : public base::Thread { |
protected: |
virtual void Init() { |
+#if defined(OS_WIN) |
CoInitialize(NULL); |
+#endif |
bool rv = RenderProcess::GlobalInit(channel_id_); |
DCHECK(rv); |
@@ -80,7 +92,9 @@ class RendererMainThread : public base::Thread { |
virtual void CleanUp() { |
RenderProcess::GlobalCleanup(); |
+#if defined(OS_WIN) |
CoUninitialize(); |
+#endif |
} |
private: |
@@ -139,7 +153,6 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() { |
channel_.reset(); |
if (process_.handle() && !run_renderer_in_process()) { |
- watcher_.StopWatching(); |
ProcessWatcher::EnsureProcessTerminated(process_.handle()); |
} |
@@ -149,6 +162,27 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() { |
NOTIFY_USER_SCRIPTS_LOADED, NotificationService::AllSources()); |
} |
+// When we're started with the --start-renderers-manually flag, we pop up a |
+// modal dialog requesting the user manually start up a renderer. |
+// |cmd_line| is the command line to start the renderer with. |
+static void RunStartRenderersManuallyDialog(const CommandLine& cmd_line) { |
+#if defined(OS_WIN) |
+ std::wstring message = |
+ L"Please start a renderer process using:\n" + |
+ cmd_line.command_line_string(); |
+ |
+ // We don't know the owner window for RenderProcessHost and therefore we |
+ // pass a NULL HWND argument. |
+ win_util::MessageBox(NULL, |
+ message, |
+ switches::kBrowserStartRenderersManually, |
+ MB_OK); |
+#else |
+ // TODO(port): refactor above code / pop up a message box here. |
+ NOTIMPLEMENTED(); |
+#endif |
+} |
+ |
bool BrowserRenderProcessHost::Init() { |
// calling Init() more than once does nothing, this makes it more convenient |
// for the view host which may not be sure in some cases |
@@ -170,7 +204,7 @@ bool BrowserRenderProcessHost::Init() { |
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); |
// setup IPC channel |
- std::wstring channel_id = GenerateRandomChannelID(this); |
+ const std::wstring channel_id = GenerateRandomChannelID(this); |
channel_.reset( |
new IPC::SyncChannel(channel_id, IPC::Channel::MODE_SERVER, this, |
resource_message_filter, |
@@ -226,7 +260,7 @@ bool BrowserRenderProcessHost::Init() { |
switches::kEnableVideo, |
}; |
- for (int i = 0; i < arraysize(switch_names); ++i) { |
+ for (size_t i = 0; i < arraysize(switch_names); ++i) { |
if (browser_command_line.HasSwitch(switch_names[i])) { |
cmd_line.AppendSwitchWithValue(switch_names[i], |
browser_command_line.GetSwitchValue(switch_names[i])); |
@@ -243,10 +277,13 @@ bool BrowserRenderProcessHost::Init() { |
in_sandbox = false; |
} |
+#if defined(OS_WIN) |
bool child_needs_help = |
DebugFlags::ProcessDebugFlags(&cmd_line, |
DebugFlags::RENDERER, |
in_sandbox); |
+#endif |
+ |
cmd_line.AppendSwitchWithValue(switches::kProcessType, |
switches::kRendererProcess); |
@@ -281,17 +318,9 @@ bool BrowserRenderProcessHost::Init() { |
if (g_browser_process->local_state() && |
g_browser_process->local_state()->GetBoolean( |
prefs::kStartRenderersManually)) { |
- std::wstring message = |
- L"Please start a renderer process using:\n" + |
- cmd_line.command_line_string(); |
- |
- // We don't know the owner window for BrowserRenderProcessHost and therefore we |
- // pass a NULL HWND argument. |
- win_util::MessageBox(NULL, |
- message, |
- switches::kBrowserStartRenderersManually, |
- MB_OK); |
+ RunStartRenderersManuallyDialog(cmd_line); |
} else { |
+#if defined(OS_WIN) |
if (in_sandbox) { |
// spawn the child process in the sandbox |
sandbox::BrokerServices* broker_service = |
@@ -362,15 +391,22 @@ bool BrowserRenderProcessHost::Init() { |
// the process is in a sandbox. |
if (child_needs_help) |
DebugUtil::SpawnDebuggerOnProcess(target.dwProcessId); |
- } else { |
+ } else |
+#endif // OS_WIN and sandbox |
+ { |
+#if defined(OS_WIN) |
// spawn child process |
- HANDLE process; |
+ base::ProcessHandle process = 0; |
+ // TODO(port): LaunchApp is actually no good on POSIX when |
+ // we've constructed the command line as we have here, as the above |
+ // calls all append to a single string while LaunchApp reaches in to |
+ // the argv array. CommandLine should be fixed, but once it is, this |
+ // code will be correct. |
if (!base::LaunchApp(cmd_line, false, false, &process)) |
return false; |
process_.set_handle(process); |
+#endif |
} |
- |
- watcher_.StartWatching(process_.handle(), this); |
} |
} |
@@ -504,6 +540,7 @@ bool BrowserRenderProcessHost::FastShutdownIfPossible() { |
if (BrowserRenderProcessHost::run_renderer_in_process()) |
return false; // Since process mode can't do fast shutdown. |
+#if defined(OS_WIN) |
// Test if there's an unload listener |
BrowserRenderProcessHost::listeners_iterator iter; |
// NOTE: This is a bit dangerous. We know that for now, listeners are |
@@ -522,6 +559,13 @@ bool BrowserRenderProcessHost::FastShutdownIfPossible() { |
return false; |
} |
} |
+#else |
+ // TODO(port): the above is the only reason this file pulls in |
+ // RenderWidgetHost and RenderViewHost. |
+ // Perhaps IPC::Channel::Listener needs another method like CanTerminate()? |
+ // No matter what, some abstractions are getting broken here... |
+ NOTIMPLEMENTED(); |
+#endif |
// Otherwise, we're allowed to just terminate the process. Using exit code 0 |
// means that UMA won't treat this as a renderer crash. |
@@ -574,16 +618,20 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { |
void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) { |
// process_ is not NULL if we created the renderer process |
if (!process_.handle()) { |
- if (GetCurrentProcessId() == peer_pid) { |
+ if (base::GetCurrentProcId() == peer_pid) { |
// We are in single-process mode. In theory we should have access to |
// ourself but it may happen that we don't. |
- process_.set_handle(GetCurrentProcess()); |
+ process_.set_handle(base::GetCurrentProcessHandle()); |
} else { |
+#if defined(OS_WIN) |
// Request MAXIMUM_ALLOWED to match the access a handle |
// returned by CreateProcess() has to the process object. |
process_.set_handle(OpenProcess(MAXIMUM_ALLOWED, FALSE, peer_pid)); |
+#elif defined(OS_POSIX) |
+ // ProcessHandle is just a pid. |
+ process_.set_handle(peer_pid); |
+#endif |
DCHECK(process_.handle()); |
- watcher_.StartWatching(process_.handle(), this); |
} |
} else { |
// Need to verify that the peer_pid is actually the process we know, if |
@@ -594,23 +642,25 @@ void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) { |
// Static. This function can be called from the IO Thread or from the UI thread. |
void BrowserRenderProcessHost::BadMessageTerminateProcess(uint16 msg_type, |
- HANDLE process) { |
+ base::ProcessHandle process) { |
LOG(ERROR) << "bad message " << msg_type << " terminating renderer."; |
if (BrowserRenderProcessHost::run_renderer_in_process()) { |
// In single process mode it is better if we don't suicide but just crash. |
CHECK(false); |
} |
NOTREACHED(); |
- ::TerminateProcess(process, ResultCodes::KILLED_BAD_MESSAGE); |
+ base::KillProcess(process, ResultCodes::KILLED_BAD_MESSAGE, false); |
} |
-// indicates the renderer process has exited |
-void BrowserRenderProcessHost::OnObjectSignaled(HANDLE object) { |
+void BrowserRenderProcessHost::OnChannelError() { |
+ // Our child process has died. If we didn't expect it, it's a crash. |
+ // In any case, we need to let everyone know it's gone. |
+ |
DCHECK(process_.handle()); |
DCHECK(channel_.get()); |
- DCHECK_EQ(object, process_.handle()); |
+ base::ProcessHandle process = process_.handle(); |
- bool clean_shutdown = !base::DidProcessCrash(object); |
+ bool clean_shutdown = !base::DidProcessCrash(process); |
process_.Close(); |
@@ -629,7 +679,7 @@ void BrowserRenderProcessHost::OnObjectSignaled(HANDLE object) { |
// deleted. We therefore need a stack copy of the web view list to avoid |
// crashing when checking for the termination condition the last time. |
IDMap<IPC::Channel::Listener> local_listeners(listeners_); |
- for (IDMap<IPC::Channel::Listener>::const_iterator i = local_listeners.begin(); |
+ for (listeners_iterator i = local_listeners.begin(); |
i != local_listeners.end(); ++i) { |
i->second->OnMessageReceived(ViewHostMsg_RendererGone(i->first)); |
} |
@@ -725,3 +775,16 @@ void BrowserRenderProcessHost::Observe(NotificationType type, |
} |
} |
} |
+ |
+std::wstring GenerateRandomChannelID(void* instance) { |
+ // Note: the string must start with the current process id, this is how |
+ // child processes determine the pid of the parent. |
+ // Build the channel ID. This is composed of a unique identifier for the |
+ // parent browser process, an identifier for the renderer/plugin instance, |
+ // and a random component. We use a random component so that a hacked child |
+ // process can't cause denial of service by causing future named pipe creation |
+ // to fail. |
+ return StringPrintf(L"%d.%x.%d", |
+ base::GetCurrentProcId(), instance, |
+ base::RandInt(0, std::numeric_limits<int>::max())); |
+} |