diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-25 16:08:52 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-25 16:08:52 +0000 |
commit | f8ba13ddfaf769ade709cf4ce205a009521a7c09 (patch) | |
tree | ec017792f84d8e59493e1a5f180b0c611f30619e /chrome/app | |
parent | 0981f86e200719979691ce48a93c8532d525c06b (diff) | |
download | chromium_src-f8ba13ddfaf769ade709cf4ce205a009521a7c09.zip chromium_src-f8ba13ddfaf769ade709cf4ce205a009521a7c09.tar.gz chromium_src-f8ba13ddfaf769ade709cf4ce205a009521a7c09.tar.bz2 |
Move ZygoteForkDelegateLinux to content/public/common.
BUG=98716
Review URL: http://codereview.chromium.org/8381029
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107128 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/app')
-rw-r--r-- | chrome/app/chrome_main_delegate.cc | 4 | ||||
-rw-r--r-- | chrome/app/chrome_main_delegate.h | 2 | ||||
-rw-r--r-- | chrome/app/nacl_fork_delegate_linux.cc | 150 | ||||
-rw-r--r-- | chrome/app/nacl_fork_delegate_linux.h | 54 |
4 files changed, 207 insertions, 3 deletions
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 776b989..93ce114 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc @@ -72,7 +72,7 @@ #endif #if defined(OS_POSIX) && !defined(OS_MACOSX) -#include "chrome/common/nacl_fork_delegate_linux.h" +#include "chrome/app/nacl_fork_delegate_linux.h" #endif #if defined(OS_CHROMEOS) @@ -704,7 +704,7 @@ bool ChromeMainDelegate::DelaySandboxInitialization( process_type == switches::kRelauncherProcess; } #elif defined(OS_POSIX) -ZygoteForkDelegate* ChromeMainDelegate::ZygoteStarting() { +content::ZygoteForkDelegate* ChromeMainDelegate::ZygoteStarting() { // 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. diff --git a/chrome/app/chrome_main_delegate.h b/chrome/app/chrome_main_delegate.h index f0a6fe9..064b561 100644 --- a/chrome/app/chrome_main_delegate.h +++ b/chrome/app/chrome_main_delegate.h @@ -38,7 +38,7 @@ class ChromeMainDelegate : public content::ContentMainDelegate { virtual bool DelaySandboxInitialization( const std::string& process_type) OVERRIDE; #elif defined(OS_POSIX) - virtual ZygoteForkDelegate* ZygoteStarting() OVERRIDE; + virtual content::ZygoteForkDelegate* ZygoteStarting() OVERRIDE; virtual void ZygoteForked() OVERRIDE; #endif diff --git a/chrome/app/nacl_fork_delegate_linux.cc b/chrome/app/nacl_fork_delegate_linux.cc new file mode 100644 index 0000000..a3723a3 --- /dev/null +++ b/chrome/app/nacl_fork_delegate_linux.cc @@ -0,0 +1,150 @@ +// 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/app/nacl_fork_delegate_linux.h" + +#include <signal.h> +#include <stdlib.h> +#include <sys/socket.h> + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/eintr_wrapper.h" +#include "base/logging.h" +#include "base/file_path.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "base/third_party/dynamic_annotations/dynamic_annotations.h" +#include "content/common/unix_domain_socket_posix.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/nacl_helper_linux.h" + +NaClForkDelegate::NaClForkDelegate() + : status_(kNaClHelperUnused), + sandboxed_(false), + fd_(-1) {} + +const char kNaClHelperAtZero[] = "--at-zero"; + +void NaClForkDelegate::Init(const bool sandboxed, + const int browserdesc, + const int sandboxdesc) { + VLOG(1) << "NaClForkDelegate::Init()"; + int fds[2]; + + sandboxed_ = sandboxed; + // Confirm a couple hard-wired assumptions. + // The NaCl constants are from chrome/nacl/nacl_linux_helper.h + DCHECK(kNaClBrowserDescriptor == browserdesc); + DCHECK(kNaClSandboxDescriptor == sandboxdesc); + + 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], kNaClZygoteDescriptor)); + fds_to_map.push_back(std::make_pair(sandboxdesc, kNaClSandboxDescriptor)); + + status_ = kNaClHelperUnused; + FilePath helper_exe; + FilePath helper_bootstrap_exe; + if (!PathService::Get(chrome::FILE_NACL_HELPER, &helper_exe)) { + status_ = kNaClHelperMissing; + } else if (!PathService::Get(chrome::FILE_NACL_HELPER_BOOTSTRAP, + &helper_bootstrap_exe)) { + status_ = kNaClHelperBootstrapMissing; + } else if (RunningOnValgrind()) { + status_ = kNaClHelperValgrind; + } else { + CommandLine cmd_line(helper_bootstrap_exe); + cmd_line.AppendArgPath(helper_exe); + cmd_line.AppendArgNative(kNaClHelperAtZero); + base::LaunchOptions options; + options.fds_to_remap = &fds_to_map; + options.clone_flags = CLONE_FS | SIGCHLD; + if (!base::LaunchProcess(cmd_line.argv(), options, NULL)) + status_ = kNaClHelperLaunchFailed; + // parent and error cases are handled below + } + if (HANDLE_EINTR(close(fds[1])) != 0) + LOG(ERROR) << "close(fds[1]) failed"; + if (status_ == kNaClHelperUnused) { + const ssize_t kExpectedLength = strlen(kNaClHelperStartupAck); + char buf[kExpectedLength]; + + // Wait for ack from nacl_helper, indicating it is ready to help + const ssize_t nread = HANDLE_EINTR(read(fds[0], buf, sizeof(buf))); + if (nread == kExpectedLength && + memcmp(buf, kNaClHelperStartupAck, nread) == 0) { + // all is well + status_ = kNaClHelperSuccess; + fd_ = fds[0]; + return; + } + + status_ = kNaClHelperAckFailed; + LOG(ERROR) << "Bad NaCl helper startup ack (" << nread << " bytes)"; + } + // TODO(bradchen): Make this LOG(ERROR) when the NaCl helper + // becomes the default. + fd_ = -1; + if (HANDLE_EINTR(close(fds[0])) != 0) + LOG(ERROR) << "close(fds[0]) failed"; +} + +void NaClForkDelegate::InitialUMA(std::string* uma_name, + int* uma_sample, + int* uma_boundary_value) { + *uma_name = "NaCl.Client.Helper.InitState"; + *uma_sample = status_; + *uma_boundary_value = kNaClHelperStatusBoundary; +} + +NaClForkDelegate::~NaClForkDelegate() { + // side effect of close: delegate process will terminate + if (status_ == kNaClHelperSuccess) { + if (HANDLE_EINTR(close(fd_)) != 0) + LOG(ERROR) << "close(fd_) failed"; + } +} + +bool NaClForkDelegate::CanHelp(const std::string& process_type, + std::string* uma_name, + int* uma_sample, + int* uma_boundary_value) { + if (process_type != switches::kNaClLoaderProcess) + return false; + *uma_name = "NaCl.Client.Helper.StateOnFork"; + *uma_sample = status_; + *uma_boundary_value = kNaClHelperStatusBoundary; + return status_ == kNaClHelperSuccess; +} + +pid_t NaClForkDelegate::Fork(const std::vector<int>& fds) { + base::ProcessId naclchild; + VLOG(1) << "NaClForkDelegate::Fork"; + + DCHECK(fds.size() == kNaClParentFDIndex + 1); + if (!UnixDomainSocket::SendMsg(fd_, kNaClForkRequest, + strlen(kNaClForkRequest), fds)) { + LOG(ERROR) << "NaClForkDelegate::Fork: SendMsg failed"; + return -1; + } + int nread = HANDLE_EINTR(read(fd_, &naclchild, sizeof(naclchild))); + if (nread != sizeof(naclchild)) { + LOG(ERROR) << "NaClForkDelegate::Fork: read failed"; + return -1; + } + VLOG(1) << "nacl_child is " << naclchild << " (" << nread << " bytes)"; + return naclchild; +} + +bool NaClForkDelegate::AckChild(const int fd, + const std::string& channel_switch) { + int nwritten = HANDLE_EINTR(write(fd, channel_switch.c_str(), + channel_switch.length())); + if (nwritten != static_cast<int>(channel_switch.length())) { + return false; + } + return true; +} diff --git a/chrome/app/nacl_fork_delegate_linux.h b/chrome/app/nacl_fork_delegate_linux.h new file mode 100644 index 0000000..853df09 --- /dev/null +++ b/chrome/app/nacl_fork_delegate_linux.h @@ -0,0 +1,54 @@ +// 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_APP_NACL_FORK_DELEGATE_LINUX_H_ +#define CHROME_APP_NACL_FORK_DELEGATE_LINUX_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "content/public/common/zygote_fork_delegate_linux.h" + +// The NaClForkDelegate is created during Chrome linux zygote +// initialization, and provides "fork()" functionality with +// NaCl specific process characteristics (specifically address +// space layout) as an alternative to forking the zygote. +// A new delegate is passed in as an argument to ZygoteMain(). +class NaClForkDelegate : public content::ZygoteForkDelegate { + public: + NaClForkDelegate(); + virtual ~NaClForkDelegate(); + + virtual void Init(bool sandboxed, + int browserdesc, + int sandboxdesc) OVERRIDE; + virtual void InitialUMA(std::string* uma_name, + int* uma_sample, + int* uma_boundary_value) OVERRIDE; + virtual bool CanHelp(const std::string& process_type, std::string* uma_name, + int* uma_sample, int* uma_boundary_value) OVERRIDE; + virtual pid_t Fork(const std::vector<int>& fds) OVERRIDE; + virtual bool AckChild(int fd, + const std::string& channel_switch) OVERRIDE; + + private: + // These values are reported via UMA and hence they become permanent + // constants. Old values cannot be reused, only new ones added. + enum NaClHelperStatus { + kNaClHelperUnused = 0, + kNaClHelperMissing = 1, + kNaClHelperBootstrapMissing = 2, + kNaClHelperValgrind = 3, + kNaClHelperLaunchFailed = 4, + kNaClHelperAckFailed = 5, + kNaClHelperSuccess = 6, + kNaClHelperStatusBoundary // Must be one greater than highest value used. + }; + + NaClHelperStatus status_; + bool sandboxed_; + int fd_; +}; + +#endif // CHROME_APP_NACL_FORK_DELEGATE_LINUX_H_ |