summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormdempsky@chromium.org <mdempsky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-11 01:17:47 +0000
committermdempsky@chromium.org <mdempsky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-11 01:17:47 +0000
commit54ad01a07a6c2ffa6ee2d2ec11cd6d56b723cd5e (patch)
treeee8f209267515175b3c9c11a52c1fce9a699c675
parent5cf28ab789a0fa2faf5050b8a60e296f25e808c6 (diff)
downloadchromium_src-54ad01a07a6c2ffa6ee2d2ec11cd6d56b723cd5e.zip
chromium_src-54ad01a07a6c2ffa6ee2d2ec11cd6d56b723cd5e.tar.gz
chromium_src-54ad01a07a6c2ffa6ee2d2ec11cd6d56b723cd5e.tar.bz2
Add support for multiple zygote fork delegates
No functional changes yet, just preparation for splitting NaCl's fork delegate into two different implementations. BUG=364945 Review URL: https://codereview.chromium.org/269413004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269673 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/chrome_main_delegate.cc9
-rw-r--r--chrome/app/chrome_main_delegate.h6
-rw-r--r--content/app/content_main_runner.cc7
-rw-r--r--content/public/app/content_main_delegate.cc4
-rw-r--r--content/public/app/content_main_delegate.h8
-rw-r--r--content/public/common/zygote_fork_delegate_linux.h6
-rw-r--r--content/zygote/zygote_linux.cc61
-rw-r--r--content/zygote/zygote_linux.h19
-rw-r--r--content/zygote/zygote_main.h5
-rw-r--r--content/zygote/zygote_main_linux.cc16
10 files changed, 74 insertions, 67 deletions
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 2c29876..486cd42 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -855,11 +855,10 @@ bool ChromeMainDelegate::DelaySandboxInitialization(
process_type == switches::kRelauncherProcess;
}
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
-content::ZygoteForkDelegate* ChromeMainDelegate::ZygoteStarting() {
-#if defined(DISABLE_NACL)
- return NULL;
-#else
- return new NaClForkDelegate();
+void ChromeMainDelegate::ZygoteStarting(
+ ScopedVector<content::ZygoteForkDelegate>* delegates) {
+#if !defined(DISABLE_NACL)
+ delegates->push_back(new NaClForkDelegate());
#endif
}
diff --git a/chrome/app/chrome_main_delegate.h b/chrome/app/chrome_main_delegate.h
index 5b651fe..d0707ed 100644
--- a/chrome/app/chrome_main_delegate.h
+++ b/chrome/app/chrome_main_delegate.h
@@ -10,6 +10,9 @@
#include "chrome/common/chrome_content_client.h"
#include "content/public/app/content_main_delegate.h"
+template <typename>
+class ScopedVector;
+
namespace base {
class CommandLine;
}
@@ -36,7 +39,8 @@ class ChromeMainDelegate : public content::ContentMainDelegate {
virtual bool DelaySandboxInitialization(
const std::string& process_type) OVERRIDE;
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
- virtual content::ZygoteForkDelegate* ZygoteStarting() OVERRIDE;
+ virtual void ZygoteStarting(
+ ScopedVector<content::ZygoteForkDelegate>* delegates) OVERRIDE;
virtual void ZygoteForked() OVERRIDE;
#endif
virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 2593b28..24a5289 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -16,6 +16,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/metrics/stats_table.h"
#include "base/path_service.h"
#include "base/process/launch.h"
@@ -298,9 +299,9 @@ int RunZygote(const MainFunctionParams& main_function_params,
{ switches::kUtilityProcess, UtilityMain },
};
- scoped_ptr<ZygoteForkDelegate> zygote_fork_delegate;
+ ScopedVector<ZygoteForkDelegate> zygote_fork_delegates;
if (delegate) {
- zygote_fork_delegate.reset(delegate->ZygoteStarting());
+ delegate->ZygoteStarting(&zygote_fork_delegates);
// Each Renderer we spawn will re-attempt initialization of the media
// libraries, at which point failure will be detected and handled, so
// we do not need to cope with initialization failures here.
@@ -310,7 +311,7 @@ int RunZygote(const MainFunctionParams& main_function_params,
}
// This function call can return multiple times, once per fork().
- if (!ZygoteMain(main_function_params, zygote_fork_delegate.get()))
+ if (!ZygoteMain(main_function_params, zygote_fork_delegates.Pass()))
return 1;
if (delegate) delegate->ZygoteForked();
diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc
index 88ce4aa..433300c 100644
--- a/content/public/app/content_main_delegate.cc
+++ b/content/public/app/content_main_delegate.cc
@@ -42,8 +42,8 @@ bool ContentMainDelegate::DelaySandboxInitialization(
#elif defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
-ZygoteForkDelegate* ContentMainDelegate::ZygoteStarting() {
- return NULL;
+void ContentMainDelegate::ZygoteStarting(
+ ScopedVector<ZygoteForkDelegate>* delegates) {
}
#endif
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h
index 9b94b98..6191d78 100644
--- a/content/public/app/content_main_delegate.h
+++ b/content/public/app/content_main_delegate.h
@@ -10,6 +10,9 @@
#include "build/build_config.h"
#include "content/common/content_export.h"
+template <typename>
+class ScopedVector;
+
namespace content {
class ContentBrowserClient;
@@ -65,8 +68,9 @@ class CONTENT_EXPORT ContentMainDelegate {
#elif defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
// Tells the embedder that the zygote process is starting, and allows it to
- // specify a zygote delegate if it wishes.
- virtual ZygoteForkDelegate* ZygoteStarting();
+ // specify one or more zygote delegates if it wishes by storing them in
+ // |*delegates|.
+ virtual void ZygoteStarting(ScopedVector<ZygoteForkDelegate>* delegates);
// Called every time the zygote process forks.
virtual void ZygoteForked() {}
diff --git a/content/public/common/zygote_fork_delegate_linux.h b/content/public/common/zygote_fork_delegate_linux.h
index 66f99cd..2f2f0b2 100644
--- a/content/public/common/zygote_fork_delegate_linux.h
+++ b/content/public/common/zygote_fork_delegate_linux.h
@@ -33,8 +33,10 @@ class ZygoteForkDelegate {
// layer-1 sandbox such as the setuid sandbox.
virtual void Init(int sandboxdesc, bool enable_layer1_sandbox) = 0;
- // After Init, supply a UMA_HISTOGRAM_ENUMERATION the delegate
- // would like to supply on the first fork.
+ // After Init, supply a UMA_HISTOGRAM_ENUMERATION the delegate would like
+ // reported to the browser process. (Note: Because these reports are
+ // piggy-backed onto fork responses that don't otherwise contain UMA reports,
+ // this method may not be called until much later.)
virtual void InitialUMA(std::string* uma_name,
int* uma_sample,
int* uma_boundary_value) = 0;
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc
index 5f922a4..b518673 100644
--- a/content/zygote/zygote_linux.cc
+++ b/content/zygote/zygote_linux.cc
@@ -16,6 +16,7 @@
#include "base/linux_util.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/global_descriptors.h"
@@ -57,8 +58,8 @@ void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
write_pipe->reset(raw_pipe[1]);
}
-void KillAndReap(pid_t pid, bool use_helper) {
- if (use_helper) {
+void KillAndReap(pid_t pid, ZygoteForkDelegate* helper) {
+ if (helper) {
// Helper children may be forked in another PID namespace, so |pid| might
// be meaningless to us; or we just might not be able to directly send it
// signals. So we can't kill it.
@@ -76,17 +77,10 @@ void KillAndReap(pid_t pid, bool use_helper) {
} // namespace
-Zygote::Zygote(int sandbox_flags,
- ZygoteForkDelegate* helper)
+Zygote::Zygote(int sandbox_flags, ScopedVector<ZygoteForkDelegate> helpers)
: sandbox_flags_(sandbox_flags),
- helper_(helper),
- initial_uma_sample_(0),
- initial_uma_boundary_value_(0) {
- if (helper_) {
- helper_->InitialUMA(&initial_uma_name_,
- &initial_uma_sample_,
- &initial_uma_boundary_value_);
- }
+ helpers_(helpers.Pass()),
+ initial_uma_index_(0) {
}
Zygote::~Zygote() {
@@ -265,9 +259,8 @@ bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid,
// We know about |real_pid|.
const base::ProcessHandle child = child_info.internal_pid;
if (child_info.started_from_helper) {
- // Let the helper handle the request.
- DCHECK(helper_);
- if (!helper_->GetTerminationStatus(child, known_dead, status, exit_code)) {
+ if (!child_info.started_from_helper->GetTerminationStatus(
+ child, known_dead, status, exit_code)) {
return false;
}
} else {
@@ -330,14 +323,19 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
std::string* uma_name,
int* uma_sample,
int* uma_boundary_value) {
- const bool use_helper = (helper_ && helper_->CanHelp(process_type,
- uma_name,
- uma_sample,
- uma_boundary_value));
+ ZygoteForkDelegate* helper = NULL;
+ for (ScopedVector<ZygoteForkDelegate>::iterator i = helpers_.begin();
+ i != helpers_.end();
+ ++i) {
+ if ((*i)->CanHelp(process_type, uma_name, uma_sample, uma_boundary_value)) {
+ helper = *i;
+ break;
+ }
+ }
base::ScopedFD read_pipe, write_pipe;
base::ProcessId pid = 0;
- if (use_helper) {
+ if (helper) {
int ipc_channel_fd = LookUpFd(fd_mapping, kPrimaryIPCChannel);
if (ipc_channel_fd < 0) {
DLOG(ERROR) << "Failed to find kPrimaryIPCChannel in FD mapping";
@@ -346,7 +344,7 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
std::vector<int> fds;
fds.push_back(ipc_channel_fd); // kBrowserFDIndex
fds.push_back(pid_oracle.get()); // kPIDOracleFDIndex
- pid = helper_->Fork(process_type, fds, channel_id);
+ pid = helper->Fork(process_type, fds, channel_id);
// Helpers should never return in the child process.
CHECK_NE(pid, 0);
@@ -416,16 +414,16 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
// If we successfully forked a child, but it crashed without sending
// a message to the browser, the browser won't have found its PID.
if (real_pid < 0) {
- KillAndReap(pid, use_helper);
+ KillAndReap(pid, helper);
return -1;
}
// If we're not using a helper, send the PID back to the child process.
- if (!use_helper) {
+ if (!helper) {
ssize_t written =
HANDLE_EINTR(write(write_pipe.get(), &real_pid, sizeof(real_pid)));
if (written != sizeof(real_pid)) {
- KillAndReap(pid, use_helper);
+ KillAndReap(pid, helper);
return -1;
}
}
@@ -436,7 +434,7 @@ int Zygote::ForkWithRealPid(const std::string& process_type,
NOTREACHED();
}
process_info_map_[real_pid].internal_pid = pid;
- process_info_map_[real_pid].started_from_helper = use_helper;
+ process_info_map_[real_pid].started_from_helper = helper;
return real_pid;
}
@@ -538,14 +536,11 @@ bool Zygote::HandleForkRequest(int fd,
pickle, iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value);
if (child_pid == 0)
return true;
- if (uma_name.empty()) {
- // There is no UMA report from this particular fork.
- // Use the initial UMA report if any, and clear that record for next time.
- // Note the swap method here is the efficient way to do this, since
- // we know uma_name is empty.
- uma_name.swap(initial_uma_name_);
- uma_sample = initial_uma_sample_;
- uma_boundary_value = initial_uma_boundary_value_;
+ // If there's no UMA report for this particular fork, then check if any
+ // helpers have an initial UMA report for us to send instead.
+ while (uma_name.empty() && initial_uma_index_ < helpers_.size()) {
+ helpers_[initial_uma_index_++]->InitialUMA(
+ &uma_name, &uma_sample, &uma_boundary_value);
}
// Must always send reply, as ZygoteHost blocks while waiting for it.
Pickle reply_pickle;
diff --git a/content/zygote/zygote_linux.h b/content/zygote/zygote_linux.h
index 8e1996c..ef7e071 100644
--- a/content/zygote/zygote_linux.h
+++ b/content/zygote/zygote_linux.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_ZYGOTE_ZYGOTE_H_
#define CONTENT_ZYGOTE_ZYGOTE_H_
+#include <stddef.h>
+
#include <string>
#include "base/containers/small_map.h"
@@ -26,8 +28,7 @@ class ZygoteForkDelegate;
// runs it.
class Zygote {
public:
- Zygote(int sandbox_flags,
- ZygoteForkDelegate* helper);
+ Zygote(int sandbox_flags, ScopedVector<ZygoteForkDelegate> helpers);
~Zygote();
bool ProcessRequests();
@@ -36,9 +37,8 @@ class Zygote {
struct ZygoteProcessInfo {
// Pid from inside the Zygote's PID namespace.
base::ProcessHandle internal_pid;
- // Keeps track of whether or not a process was started from a fork
- // delegate helper.
- bool started_from_helper;
+ // Keeps track of which fork delegate helper the process was started from.
+ ZygoteForkDelegate* started_from_helper;
};
typedef base::SmallMap< std::map<base::ProcessHandle, ZygoteProcessInfo> >
ZygoteProcessMap;
@@ -119,13 +119,10 @@ class Zygote {
ZygoteProcessMap process_info_map_;
const int sandbox_flags_;
- ZygoteForkDelegate* helper_;
+ ScopedVector<ZygoteForkDelegate> helpers_;
- // These might be set by helper_->InitialUMA. They supply a UMA enumeration
- // sample we should report on the first fork.
- std::string initial_uma_name_;
- int initial_uma_sample_;
- int initial_uma_boundary_value_;
+ // Count of how many fork delegates for which we've invoked InitialUMA().
+ size_t initial_uma_index_;
};
} // namespace content
diff --git a/content/zygote/zygote_main.h b/content/zygote/zygote_main.h
index 6470232..119210f 100644
--- a/content/zygote/zygote_main.h
+++ b/content/zygote/zygote_main.h
@@ -5,13 +5,16 @@
#ifndef CONTENT_ZYGOTE_ZYGOTE_MAIN_H_
#define CONTENT_ZYGOTE_ZYGOTE_MAIN_H_
+template <typename>
+class ScopedVector;
+
namespace content {
struct MainFunctionParams;
class ZygoteForkDelegate;
bool ZygoteMain(const MainFunctionParams& params,
- ZygoteForkDelegate* forkdelegate);
+ ScopedVector<ZygoteForkDelegate> fork_delegates);
} // namespace content
diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc
index 11f0602..1232969 100644
--- a/content/zygote/zygote_main_linux.cc
+++ b/content/zygote/zygote_main_linux.cc
@@ -21,6 +21,7 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/linux_util.h"
+#include "base/memory/scoped_vector.h"
#include "base/native_library.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
@@ -442,7 +443,7 @@ static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox,
}
bool ZygoteMain(const MainFunctionParams& params,
- ZygoteForkDelegate* forkdelegate) {
+ ScopedVector<ZygoteForkDelegate> fork_delegates) {
g_am_zygote_or_renderer = true;
sandbox::InitLibcUrandomOverrides();
@@ -462,11 +463,12 @@ bool ZygoteMain(const MainFunctionParams& params,
std::vector<int>()));
}
- if (forkdelegate != NULL) {
- VLOG(1) << "ZygoteMain: initializing fork delegate";
- forkdelegate->Init(GetSandboxFD(), must_enable_setuid_sandbox);
- } else {
- VLOG(1) << "ZygoteMain: fork delegate is NULL";
+ VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size()
+ << " fork delegates";
+ for (ScopedVector<ZygoteForkDelegate>::iterator i = fork_delegates.begin();
+ i != fork_delegates.end();
+ ++i) {
+ (*i)->Init(GetSandboxFD(), must_enable_setuid_sandbox);
}
// Turn on the first layer of the sandbox if the configuration warrants it.
@@ -476,7 +478,7 @@ bool ZygoteMain(const MainFunctionParams& params,
bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID;
CHECK_EQ(must_enable_setuid_sandbox, setuid_sandbox_engaged);
- Zygote zygote(sandbox_flags, forkdelegate);
+ Zygote zygote(sandbox_flags, fork_delegates.Pass());
// This function call can return multiple times, once per fork().
return zygote.ProcessRequests();
}