summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/plugin_process_host.cc12
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc75
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h3
-rw-r--r--chrome/browser/zygote_host_linux.cc90
-rw-r--r--chrome/browser/zygote_host_linux.h41
-rw-r--r--chrome/browser/zygote_main_linux.cc168
6 files changed, 362 insertions, 27 deletions
diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc
index 921f860..5216755 100644
--- a/chrome/browser/plugin_process_host.cc
+++ b/chrome/browser/plugin_process_host.cc
@@ -14,6 +14,9 @@
#include "app/app_switches.h"
#include "base/command_line.h"
+#if defined(OS_POSIX)
+#include "base/global_descriptors_posix.h"
+#endif
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/file_version_info.h"
@@ -30,6 +33,7 @@
#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/browser/renderer_host/render_process_host.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"
@@ -393,10 +397,10 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
// 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;
- int src_fd = -1, dest_fd = -1;
- channel().GetClientFileDescriptorMapping(&src_fd, &dest_fd);
- if (src_fd > -1)
- fds_to_map.push_back(std::pair<int, int>(src_fd, dest_fd));
+ 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);
#endif
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 829ef47..29e7ef0 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -22,7 +22,6 @@
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/rand_util.h"
-#include "base/reserved_file_descriptors.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
#include "base/singleton.h"
@@ -35,9 +34,6 @@
#include "chrome/browser/history/history.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/profile.h"
-#if defined(OS_LINUX)
-#include "chrome/browser/renderer_host/render_crash_handler_host_linux.h"
-#endif
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_helper.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -45,6 +41,7 @@
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/visitedlink_master.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/child_process_info.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_service.h"
@@ -54,6 +51,11 @@
#include "chrome/renderer/render_process.h"
#include "grit/generated_resources.h"
+#if defined(OS_LINUX)
+#include "chrome/browser/zygote_host_linux.h"
+#include "chrome/browser/renderer_host/render_crash_handler_host_linux.h"
+#endif
+
using WebKit::WebCache;
#if defined(OS_WIN)
@@ -134,7 +136,8 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
backgrounded_(true),
ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_(
base::TimeDelta::FromSeconds(5),
- this, &BrowserRenderProcessHost::ClearTransportDIBCache)) {
+ this, &BrowserRenderProcessHost::ClearTransportDIBCache)),
+ zygote_child_(false) {
widget_helper_ = new RenderWidgetHelper();
registrar_.Add(this, NotificationType::USER_SCRIPTS_UPDATED,
@@ -170,7 +173,13 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() {
audio_renderer_host_->Destroy();
if (process_.handle() && !run_renderer_in_process()) {
- ProcessWatcher::EnsureProcessTerminated(process_.handle());
+ if (zygote_child_) {
+#if defined(OS_LINUX)
+ Singleton<ZygoteHost>()->EnsureProcessTerminated(process_.handle());
+#endif
+ } else {
+ ProcessWatcher::EnsureProcessTerminated(process_.handle());
+ }
}
ClearTransportDIBCache();
@@ -294,7 +303,9 @@ bool BrowserRenderProcessHost::Init() {
ASCIIToWide(field_trial->MakePersistentString()));
#if defined(OS_POSIX)
- if (browser_command_line.HasSwitch(switches::kRendererCmdPrefix)) {
+ const bool has_cmd_prefix =
+ browser_command_line.HasSwitch(switches::kRendererCmdPrefix);
+ if (has_cmd_prefix) {
// launch the renderer child with some prefix (usually "gdb --args")
const std::wstring prefix =
browser_command_line.GetSwitchValue(switches::kRendererCmdPrefix);
@@ -334,24 +345,42 @@ bool BrowserRenderProcessHost::Init() {
base::ProcessHandle process = 0;
#if defined(OS_WIN)
process = sandbox::StartProcess(&cmd_line);
-#else
- // NOTE: This code is duplicated with plugin_process_host.cc, but
- // there's not a good place to de-duplicate it.
- base::file_handle_mapping_vector fds_to_map;
- int src_fd = -1, dest_fd = -1;
- channel_->GetClientFileDescriptorMapping(&src_fd, &dest_fd);
- if (src_fd > -1)
- fds_to_map.push_back(std::pair<int, int>(src_fd, dest_fd));
+#elif defined(OS_POSIX)
#if defined(OS_LINUX)
- const int crash_signal_fd =
- Singleton<RenderCrashHandlerHostLinux>()->GetDeathSignalSocket();
- if (crash_signal_fd >= 0)
- fds_to_map.push_back(std::make_pair(crash_signal_fd, kMagicCrashSignalFd));
- base::ForkApp(cmd_line.argv(), fds_to_map, &process);
-#else
- base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
+ if (!has_cmd_prefix) {
+ base::GlobalDescriptors::Mapping mapping;
+ const int ipcfd = channel_->GetClientFileDescriptor();
+ mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd));
+ const int crash_signal_fd =
+ Singleton<RenderCrashHandlerHostLinux>()->GetDeathSignalSocket();
+ if (crash_signal_fd >= 0) {
+ mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal,
+ crash_signal_fd));
+ }
+ process = Singleton<ZygoteHost>()->ForkRenderer(cmd_line.argv(), mapping);
+ zygote_child_ = true;
+ } else {
#endif
+ // NOTE: This code is duplicated with plugin_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();
+ fds_to_map.push_back(std::make_pair(ipcfd, kPrimaryIPCChannel + 3));
+#if defined(OS_LINUX)
+ const int crash_signal_fd =
+ Singleton<RenderCrashHandlerHostLinux>()->GetDeathSignalSocket();
+ if (crash_signal_fd >= 0) {
+ fds_to_map.push_back(std::make_pair(crash_signal_fd,
+ kCrashDumpSignal + 3));
+ }
#endif
+ base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
+ zygote_child_ = false;
+#if defined(OS_LINUX)
+ }
+#endif
+#endif
+
if (!process) {
channel_.reset();
return false;
@@ -666,7 +695,7 @@ void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) {
const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
if (cmd_line.HasSwitch(switches::kRendererCmdPrefix))
return;
- CHECK(peer_pid == process_.pid());
+ CHECK(peer_pid == process_.pid()) << peer_pid << " " << process_.pid();
}
}
}
diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h
index b380211..6c259f0 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -154,6 +154,9 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// Used in single-process mode.
scoped_ptr<RendererMainThread> in_process_renderer_;
+ // True iff the renderer is a child of a zygote process.
+ bool zygote_child_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserRenderProcessHost);
};
diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc
new file mode 100644
index 0000000..f56e6e93
--- /dev/null
+++ b/chrome/browser/zygote_host_linux.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2009 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/browser/zygote_host_linux.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/pickle.h"
+#include "base/process_util.h"
+#include "base/unix_domain_socket_posix.h"
+
+#include "chrome/common/chrome_switches.h"
+
+ZygoteHost::ZygoteHost() {
+ std::wstring chrome_path;
+ CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
+ CommandLine cmd_line(chrome_path);
+
+ cmd_line.AppendSwitchWithValue(switches::kProcessType,
+ switches::kZygoteProcess);
+
+ int fds[2];
+ CHECK(socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
+ base::file_handle_mapping_vector fds_to_map;
+ fds_to_map.push_back(std::make_pair(fds[1], 3));
+
+ const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) {
+ const std::wstring prefix =
+ browser_command_line.GetSwitchValue(switches::kZygoteCmdPrefix);
+ cmd_line.PrependWrapper(prefix);
+ }
+
+ base::ProcessHandle process;
+ base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
+ CHECK(process != -1) << "Failed to launch zygote process";
+
+ close(fds[1]);
+ control_fd_ = fds[0];
+}
+
+ZygoteHost::~ZygoteHost() {
+ close(control_fd_);
+}
+
+pid_t ZygoteHost::ForkRenderer(
+ const std::vector<std::string>& argv,
+ const base::GlobalDescriptors::Mapping& mapping) {
+ Pickle pickle;
+
+ pickle.WriteInt(kCmdFork);
+ pickle.WriteInt(argv.size());
+ for (std::vector<std::string>::const_iterator
+ i = argv.begin(); i != argv.end(); ++i)
+ pickle.WriteString(*i);
+
+ pickle.WriteInt(mapping.size());
+
+ std::vector<int> fds;
+ for (base::GlobalDescriptors::Mapping::const_iterator
+ i = mapping.begin(); i != mapping.end(); ++i) {
+ pickle.WriteUInt32(i->first);
+ fds.push_back(i->second);
+ }
+
+ if (!base::SendMsg(control_fd_, pickle.data(), pickle.size(), fds))
+ return -1;
+
+ pid_t pid;
+ if (HANDLE_EINTR(read(control_fd_, &pid, sizeof(pid))) != sizeof(pid))
+ return -1;
+
+ return pid;
+}
+
+void ZygoteHost::EnsureProcessTerminated(pid_t process) {
+ Pickle pickle;
+
+ pickle.WriteInt(kCmdReap);
+ pickle.WriteInt(process);
+
+ HANDLE_EINTR(write(control_fd_, pickle.data(), pickle.size()));
+}
diff --git a/chrome/browser/zygote_host_linux.h b/chrome/browser/zygote_host_linux.h
new file mode 100644
index 0000000..279918d
--- /dev/null
+++ b/chrome/browser/zygote_host_linux.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2009 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_BROWSER_ZYGOTE_HOST_LINUX_H_
+#define CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
+
+#include <string>
+#include <vector>
+
+#include "base/global_descriptors_posix.h"
+#include "base/singleton.h"
+
+// http://code.google.com/p/chromium/wiki/LinuxZygote
+
+// The zygote host is the interface, in the browser process, to the zygote
+// process.
+class ZygoteHost {
+ public:
+ ~ZygoteHost();
+
+ pid_t ForkRenderer(const std::vector<std::string>& command_line,
+ const base::GlobalDescriptors::Mapping& mapping);
+ void EnsureProcessTerminated(pid_t process);
+
+ // These are the command codes used on the wire between the browser and the
+ // zygote.
+ enum {
+ kCmdFork = 0, // Fork off a new renderer.
+ kCmdReap = 1, // Reap a renderer child.
+ };
+
+ private:
+ friend struct DefaultSingletonTraits<ZygoteHost>;
+ ZygoteHost();
+ void LaunchZygoteProcess();
+
+ int control_fd_; // the socket to the zygote
+};
+
+#endif // CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc
new file mode 100644
index 0000000..d450c39
--- /dev/null
+++ b/chrome/browser/zygote_main_linux.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2009 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 <unistd.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/global_descriptors_posix.h"
+#include "base/pickle.h"
+#include "base/unix_domain_socket_posix.h"
+
+#include "chrome/browser/zygote_host_linux.h"
+#include "chrome/common/chrome_descriptors.h"
+#include "chrome/common/main_function_params.h"
+#include "chrome/common/process_watcher.h"
+
+// http://code.google.com/p/chromium/wiki/LinuxZygote
+
+// This is the object which implements the zygote. The ZygoteMain function,
+// which is called from ChromeMain, at the the bottom and simple constructs one
+// of these objects and runs it.
+class Zygote {
+ public:
+ bool ProcessRequests() {
+ // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
+ // browser on it.
+
+ // We need to accept SIGCHLD, even though our handler is a no-op because
+ // otherwise we cannot wait on children. (According to POSIX 2001.)
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIGCHLDHandler;
+ CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
+
+ for (;;) {
+ if (HandleRequestFromBrowser(3))
+ return true;
+ }
+ }
+
+ private:
+ // See comment below, where sigaction is called.
+ static void SIGCHLDHandler(int signal) { }
+
+ // ---------------------------------------------------------------------------
+ // Requests from the browser...
+
+ // Read and process a request from the browser. Returns true if we are in a
+ // new process and thus need to unwind back into ChromeMain.
+ bool HandleRequestFromBrowser(int fd) {
+ std::vector<int> fds;
+ static const unsigned kMaxMessageLength = 2048;
+ char buf[kMaxMessageLength];
+ const ssize_t len = base::RecvMsg(fd, buf, sizeof(buf), &fds);
+ if (len == -1) {
+ LOG(WARNING) << "Error reading message from browser: " << errno;
+ return false;
+ }
+
+ if (len == 0) {
+ // EOF from the browser. We should die.
+ _exit(0);
+ return false;
+ }
+
+ Pickle pickle(buf, len);
+ void* iter = NULL;
+
+ int kind;
+ if (!pickle.ReadInt(&iter, &kind))
+ goto error;
+
+ if (kind == ZygoteHost::kCmdFork) {
+ return HandleForkRequest(fd, pickle, iter, fds);
+ } else if (kind == ZygoteHost::kCmdReap) {
+ if (fds.size())
+ goto error;
+ return HandleReapRequest(fd, pickle, iter);
+ }
+
+ error:
+ LOG(WARNING) << "Error parsing message from browser";
+ for (std::vector<int>::const_iterator
+ i = fds.begin(); i != fds.end(); ++i)
+ close(*i);
+ return false;
+ }
+
+ bool HandleReapRequest(int fd, Pickle& pickle, void* iter) {
+ pid_t child;
+
+ if (!pickle.ReadInt(&iter, &child)) {
+ LOG(WARNING) << "Error parsing reap request from browser";
+ return false;
+ }
+
+ ProcessWatcher::EnsureProcessTerminated(child);
+
+ return false;
+ }
+
+ // Handle a 'fork' request from the browser: this means that the browser
+ // wishes to start a new renderer.
+ bool HandleForkRequest(int fd, Pickle& pickle, void* iter,
+ std::vector<int>& fds) {
+ std::vector<std::string> args;
+ int argc, numfds;
+ base::GlobalDescriptors::Mapping mapping;
+ pid_t child;
+
+ if (!pickle.ReadInt(&iter, &argc))
+ goto error;
+
+ for (int i = 0; i < argc; ++i) {
+ std::string arg;
+ if (!pickle.ReadString(&iter, &arg))
+ goto error;
+ args.push_back(arg);
+ }
+
+ if (!pickle.ReadInt(&iter, &numfds))
+ goto error;
+ if (numfds != static_cast<int>(fds.size()))
+ goto error;
+
+ for (int i = 0; i < numfds; ++i) {
+ base::GlobalDescriptors::Key key;
+ if (!pickle.ReadUInt32(&iter, &key))
+ goto error;
+ mapping.push_back(std::make_pair(key, fds[i]));
+ }
+
+ child = fork();
+
+ if (!child) {
+ close(3); // our socket from the browser is in fd 3
+ Singleton<base::GlobalDescriptors>()->Reset(mapping);
+ CommandLine::Reset();
+ CommandLine::Init(args);
+ return true;
+ }
+
+ for (std::vector<int>::const_iterator
+ i = fds.begin(); i != fds.end(); ++i)
+ close(*i);
+
+ HANDLE_EINTR(write(fd, &child, sizeof(child)));
+ return false;
+
+ error:
+ LOG(WARNING) << "Error parsing fork request from browser";
+ for (std::vector<int>::const_iterator
+ i = fds.begin(); i != fds.end(); ++i)
+ close(*i);
+ return false;
+ }
+ // ---------------------------------------------------------------------------
+};
+
+bool ZygoteMain(const MainFunctionParams& params) {
+ Zygote zygote;
+ return zygote.ProcessRequests();
+}