diff options
author | mdempsky@chromium.org <mdempsky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-11 01:17:47 +0000 |
---|---|---|
committer | mdempsky@chromium.org <mdempsky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-11 01:17:47 +0000 |
commit | 54ad01a07a6c2ffa6ee2d2ec11cd6d56b723cd5e (patch) | |
tree | ee8f209267515175b3c9c11a52c1fce9a699c675 | |
parent | 5cf28ab789a0fa2faf5050b8a60e296f25e808c6 (diff) | |
download | chromium_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.cc | 9 | ||||
-rw-r--r-- | chrome/app/chrome_main_delegate.h | 6 | ||||
-rw-r--r-- | content/app/content_main_runner.cc | 7 | ||||
-rw-r--r-- | content/public/app/content_main_delegate.cc | 4 | ||||
-rw-r--r-- | content/public/app/content_main_delegate.h | 8 | ||||
-rw-r--r-- | content/public/common/zygote_fork_delegate_linux.h | 6 | ||||
-rw-r--r-- | content/zygote/zygote_linux.cc | 61 | ||||
-rw-r--r-- | content/zygote/zygote_linux.h | 19 | ||||
-rw-r--r-- | content/zygote/zygote_main.h | 5 | ||||
-rw-r--r-- | content/zygote/zygote_main_linux.cc | 16 |
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(); } |