| Index: chrome/browser/child_process_launcher.cc
|
| ===================================================================
|
| --- chrome/browser/child_process_launcher.cc (revision 75626)
|
| +++ chrome/browser/child_process_launcher.cc (working copy)
|
| @@ -1,348 +0,0 @@
|
| -// Copyright (c) 2010 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/child_process_launcher.h"
|
| -
|
| -#include <utility> // For std::pair.
|
| -
|
| -#include "base/command_line.h"
|
| -#include "base/logging.h"
|
| -#include "base/scoped_ptr.h"
|
| -#include "base/synchronization/lock.h"
|
| -#include "base/threading/thread.h"
|
| -#include "chrome/browser/browser_thread.h"
|
| -#include "chrome/common/chrome_descriptors.h"
|
| -#include "chrome/common/chrome_switches.h"
|
| -#include "chrome/common/process_watcher.h"
|
| -#include "chrome/common/result_codes.h"
|
| -
|
| -#if defined(OS_WIN)
|
| -#include "base/file_path.h"
|
| -#include "chrome/common/sandbox_policy.h"
|
| -#elif defined(OS_LINUX)
|
| -#include "base/singleton.h"
|
| -#include "chrome/browser/crash_handler_host_linux.h"
|
| -#include "chrome/browser/zygote_host_linux.h"
|
| -#include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
|
| -#endif
|
| -
|
| -#if defined(OS_MACOSX)
|
| -#include "chrome/browser/mach_broker_mac.h"
|
| -#endif
|
| -
|
| -#if defined(OS_POSIX)
|
| -#include "base/global_descriptors_posix.h"
|
| -#endif
|
| -
|
| -// Having the functionality of ChildProcessLauncher be in an internal
|
| -// ref counted object allows us to automatically terminate the process when the
|
| -// parent class destructs, while still holding on to state that we need.
|
| -class ChildProcessLauncher::Context
|
| - : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
|
| - public:
|
| - Context()
|
| - : client_(NULL),
|
| - client_thread_id_(BrowserThread::UI),
|
| - starting_(true)
|
| -#if defined(OS_LINUX)
|
| - , zygote_(false)
|
| -#endif
|
| - {
|
| - }
|
| -
|
| - void Launch(
|
| -#if defined(OS_WIN)
|
| - const FilePath& exposed_dir,
|
| -#elif defined(OS_POSIX)
|
| - bool use_zygote,
|
| - const base::environment_vector& environ,
|
| - int ipcfd,
|
| -#endif
|
| - CommandLine* cmd_line,
|
| - Client* client) {
|
| - client_ = client;
|
| -
|
| - CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
|
| - NewRunnableMethod(
|
| - this,
|
| - &Context::LaunchInternal,
|
| -#if defined(OS_WIN)
|
| - exposed_dir,
|
| -#elif defined(OS_POSIX)
|
| - use_zygote,
|
| - environ,
|
| - ipcfd,
|
| -#endif
|
| - cmd_line));
|
| - }
|
| -
|
| - void ResetClient() {
|
| - // No need for locking as this function gets called on the same thread that
|
| - // client_ would be used.
|
| - CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
|
| - client_ = NULL;
|
| - }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
|
| - friend class ChildProcessLauncher;
|
| -
|
| - ~Context() {
|
| - Terminate();
|
| - }
|
| -
|
| - void LaunchInternal(
|
| -#if defined(OS_WIN)
|
| - const FilePath& exposed_dir,
|
| -#elif defined(OS_POSIX)
|
| - bool use_zygote,
|
| - const base::environment_vector& env,
|
| - int ipcfd,
|
| -#endif
|
| - CommandLine* cmd_line) {
|
| - scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
|
| - base::ProcessHandle handle = base::kNullProcessHandle;
|
| -#if defined(OS_WIN)
|
| - handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir);
|
| -#elif defined(OS_POSIX)
|
| -
|
| -#if defined(OS_LINUX)
|
| - if (use_zygote) {
|
| - base::GlobalDescriptors::Mapping mapping;
|
| - mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd));
|
| - const int crash_signal_fd =
|
| - RendererCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
|
| - if (crash_signal_fd >= 0) {
|
| - mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal,
|
| - crash_signal_fd));
|
| - }
|
| - handle = ZygoteHost::GetInstance()->ForkRenderer(cmd_line->argv(),
|
| - mapping);
|
| - } else
|
| - // Fall through to the normal posix case below when we're not zygoting.
|
| -#endif
|
| - {
|
| - base::file_handle_mapping_vector fds_to_map;
|
| - fds_to_map.push_back(std::make_pair(
|
| - ipcfd,
|
| - kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
|
| -
|
| -#if defined(OS_LINUX)
|
| - // On Linux, we need to add some extra file descriptors for crash handling
|
| - // and the sandbox.
|
| - bool is_renderer =
|
| - cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
|
| - switches::kRendererProcess;
|
| - bool is_plugin =
|
| - cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
|
| - switches::kPluginProcess;
|
| - bool is_gpu =
|
| - cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
|
| - switches::kGpuProcess;
|
| -
|
| - if (is_renderer || is_plugin || is_gpu) {
|
| - int crash_signal_fd;
|
| - if (is_renderer) {
|
| - crash_signal_fd = RendererCrashHandlerHostLinux::GetInstance()->
|
| - GetDeathSignalSocket();
|
| - } else if (is_plugin) {
|
| - crash_signal_fd = PluginCrashHandlerHostLinux::GetInstance()->
|
| - GetDeathSignalSocket();
|
| - } else {
|
| - crash_signal_fd = GpuCrashHandlerHostLinux::GetInstance()->
|
| - GetDeathSignalSocket();
|
| - }
|
| - if (crash_signal_fd >= 0) {
|
| - fds_to_map.push_back(std::make_pair(
|
| - crash_signal_fd,
|
| - kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor));
|
| - }
|
| - }
|
| - if (is_renderer) {
|
| - const int sandbox_fd =
|
| - RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
|
| - fds_to_map.push_back(std::make_pair(
|
| - sandbox_fd,
|
| - kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
|
| - }
|
| -#endif // defined(OS_LINUX)
|
| -
|
| - bool launched = false;
|
| -#if defined(OS_MACOSX)
|
| - // It is possible for the child process to die immediately after
|
| - // launching. To prevent leaking MachBroker map entries in this case,
|
| - // lock around all of LaunchApp(). If the child dies, the death
|
| - // notification will be processed by the MachBroker after the call to
|
| - // AddPlaceholderForPid(), enabling proper cleanup.
|
| - { // begin scope for AutoLock
|
| - MachBroker* broker = MachBroker::GetInstance();
|
| - base::AutoLock lock(broker->GetLock());
|
| -
|
| - // This call to |PrepareForFork()| will start the MachBroker listener
|
| - // thread, if it is not already running. Therefore the browser process
|
| - // will be listening for Mach IPC before LaunchApp() is called.
|
| - broker->PrepareForFork();
|
| -#endif
|
| - // Actually launch the app.
|
| - launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map,
|
| - /* wait= */false, &handle);
|
| -#if defined(OS_MACOSX)
|
| - if (launched)
|
| - broker->AddPlaceholderForPid(handle);
|
| - } // end scope for AutoLock
|
| -#endif
|
| - if (!launched)
|
| - handle = base::kNullProcessHandle;
|
| - }
|
| -#endif // else defined(OS_POSIX)
|
| -
|
| - BrowserThread::PostTask(
|
| - client_thread_id_, FROM_HERE,
|
| - NewRunnableMethod(
|
| - this,
|
| - &ChildProcessLauncher::Context::Notify,
|
| -#if defined(OS_LINUX)
|
| - use_zygote,
|
| -#endif
|
| - handle));
|
| - }
|
| -
|
| - void Notify(
|
| -#if defined(OS_LINUX)
|
| - bool zygote,
|
| -#endif
|
| - base::ProcessHandle handle) {
|
| - starting_ = false;
|
| - process_.set_handle(handle);
|
| -#if defined(OS_LINUX)
|
| - zygote_ = zygote;
|
| -#endif
|
| - if (client_) {
|
| - client_->OnProcessLaunched();
|
| - } else {
|
| - Terminate();
|
| - }
|
| - }
|
| -
|
| - void Terminate() {
|
| - if (!process_.handle())
|
| - return;
|
| -
|
| - // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
|
| - // don't this on the UI/IO threads.
|
| - BrowserThread::PostTask(
|
| - BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
|
| - NewRunnableFunction(
|
| - &ChildProcessLauncher::Context::TerminateInternal,
|
| -#if defined(OS_LINUX)
|
| - zygote_,
|
| -#endif
|
| - process_.handle()));
|
| - process_.set_handle(base::kNullProcessHandle);
|
| - }
|
| -
|
| - static void TerminateInternal(
|
| -#if defined(OS_LINUX)
|
| - bool zygote,
|
| -#endif
|
| - base::ProcessHandle handle) {
|
| - base::Process process(handle);
|
| - // Client has gone away, so just kill the process. Using exit code 0
|
| - // means that UMA won't treat this as a crash.
|
| - process.Terminate(ResultCodes::NORMAL_EXIT);
|
| - // On POSIX, we must additionally reap the child.
|
| -#if defined(OS_POSIX)
|
| -#if defined(OS_LINUX)
|
| - if (zygote) {
|
| - // If the renderer was created via a zygote, we have to proxy the reaping
|
| - // through the zygote process.
|
| - ZygoteHost::GetInstance()->EnsureProcessTerminated(handle);
|
| - } else
|
| -#endif // OS_LINUX
|
| - {
|
| - ProcessWatcher::EnsureProcessTerminated(handle);
|
| - }
|
| -#endif // OS_POSIX
|
| - process.Close();
|
| - }
|
| -
|
| - Client* client_;
|
| - BrowserThread::ID client_thread_id_;
|
| - base::Process process_;
|
| - bool starting_;
|
| -
|
| -#if defined(OS_LINUX)
|
| - bool zygote_;
|
| -#endif
|
| -};
|
| -
|
| -
|
| -ChildProcessLauncher::ChildProcessLauncher(
|
| -#if defined(OS_WIN)
|
| - const FilePath& exposed_dir,
|
| -#elif defined(OS_POSIX)
|
| - bool use_zygote,
|
| - const base::environment_vector& environ,
|
| - int ipcfd,
|
| -#endif
|
| - CommandLine* cmd_line,
|
| - Client* client) {
|
| - context_ = new Context();
|
| - context_->Launch(
|
| -#if defined(OS_WIN)
|
| - exposed_dir,
|
| -#elif defined(OS_POSIX)
|
| - use_zygote,
|
| - environ,
|
| - ipcfd,
|
| -#endif
|
| - cmd_line,
|
| - client);
|
| -}
|
| -
|
| -ChildProcessLauncher::~ChildProcessLauncher() {
|
| - context_->ResetClient();
|
| -}
|
| -
|
| -bool ChildProcessLauncher::IsStarting() {
|
| - return context_->starting_;
|
| -}
|
| -
|
| -base::ProcessHandle ChildProcessLauncher::GetHandle() {
|
| - DCHECK(!context_->starting_);
|
| - return context_->process_.handle();
|
| -}
|
| -
|
| -base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
|
| - int* exit_code) {
|
| - base::TerminationStatus status;
|
| - base::ProcessHandle handle = context_->process_.handle();
|
| -#if defined(OS_LINUX)
|
| - if (context_->zygote_) {
|
| - status = ZygoteHost::GetInstance()->GetTerminationStatus(handle, exit_code);
|
| - } else
|
| -#endif
|
| - {
|
| - status = base::GetTerminationStatus(handle, exit_code);
|
| - }
|
| -
|
| - // POSIX: If the process crashed, then the kernel closed the socket
|
| - // for it and so the child has already died by the time we get
|
| - // here. Since GetTerminationStatus called waitpid with WNOHANG,
|
| - // it'll reap the process. However, if GetTerminationStatus didn't
|
| - // reap the child (because it was still running), we'll need to
|
| - // Terminate via ProcessWatcher. So we can't close the handle here.
|
| - if (status != base::TERMINATION_STATUS_STILL_RUNNING)
|
| - context_->process_.Close();
|
| -
|
| - return status;
|
| -}
|
| -
|
| -void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
|
| - DCHECK(!context_->starting_);
|
| - context_->process_.SetProcessBackgrounded(background);
|
| -}
|
|
|