| Index: chrome/browser/child_process_launcher.cc
|
| ===================================================================
|
| --- chrome/browser/child_process_launcher.cc (revision 44239)
|
| +++ chrome/browser/child_process_launcher.cc (working copy)
|
| @@ -1,355 +0,0 @@
|
| -// 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/child_process_launcher.h"
|
| -
|
| -#include "base/command_line.h"
|
| -#include "base/logging.h"
|
| -#include "base/scoped_ptr.h"
|
| -#include "base/thread.h"
|
| -#include "chrome/browser/chrome_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 "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
|
| -
|
| -// TODO(eroman): Debugging helper to make strings show up in mini-dumps.
|
| -// Remove after done investigating 40447.
|
| -class StackString {
|
| - public:
|
| - explicit StackString(const std::wstring& str) {
|
| - length_ = str.size();
|
| - memcpy(&buffer_[0], str.data(),
|
| - std::min(sizeof(wchar_t) * str.length(),
|
| - sizeof(buffer_)));
|
| - }
|
| -
|
| - std::wstring ToString() {
|
| - return std::wstring(buffer_, length_);
|
| - }
|
| -
|
| - ~StackString() {
|
| - // Hack to make sure compiler doesn't optimize us away.
|
| - if (ToString() != ToString())
|
| - LOG(INFO) << ToString();
|
| - }
|
| -
|
| - private:
|
| - wchar_t buffer_[128];
|
| - size_t length_;
|
| -};
|
| -
|
| -// 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()
|
| - : 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(ChromeThread::GetCurrentThreadIdentifier(&client_thread_id_));
|
| -
|
| - ChromeThread::PostTask(
|
| - ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
|
| - NewRunnableMethod(
|
| - this,
|
| - &Context::LaunchInternal,
|
| -#if defined(OS_WIN)
|
| - exposed_dir,
|
| -#elif defined(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(ChromeThread::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)
|
| - // TODO(eroman): Remove after done investigating 40447.
|
| - StackString stack_command_line(cmd_line->command_line_string());
|
| - // This line might crash, since it calls the string copy-constructor:
|
| - StackString stack_program(cmd_line->program());
|
| -
|
| - 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 =
|
| - Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket();
|
| - if (crash_signal_fd >= 0) {
|
| - mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal,
|
| - crash_signal_fd));
|
| - }
|
| - handle = Singleton<ZygoteHost>()->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;
|
| -
|
| - if (is_renderer || is_plugin) {
|
| - int crash_signal_fd;
|
| - if (is_renderer) {
|
| - crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()->
|
| - GetDeathSignalSocket();
|
| - } else {
|
| - crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()->
|
| - 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 =
|
| - Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
|
| - fds_to_map.push_back(std::make_pair(
|
| - sandbox_fd,
|
| - kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
|
| - }
|
| -#endif // defined(OS_LINUX)
|
| -
|
| - // Actually launch the app.
|
| - bool launched;
|
| -#if defined(OS_MACOSX)
|
| - task_t child_task;
|
| - launched = base::LaunchAppAndGetTask(
|
| - cmd_line->argv(), env, fds_to_map, false, &child_task, &handle);
|
| - if (launched && child_task != MACH_PORT_NULL) {
|
| - MachBroker::instance()->RegisterPid(
|
| - handle,
|
| - MachBroker::MachInfo().SetTask(child_task));
|
| - }
|
| -#else
|
| - launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map,
|
| - /* wait= */false, &handle);
|
| -#endif
|
| - if (!launched)
|
| - handle = base::kNullProcessHandle;
|
| - }
|
| -#endif // else defined(OS_POSIX)
|
| -
|
| - ChromeThread::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.
|
| - ChromeThread::PostTask(
|
| - ChromeThread::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.
|
| - Singleton<ZygoteHost>()->EnsureProcessTerminated(handle);
|
| - } else
|
| -#endif // OS_LINUX
|
| - {
|
| - ProcessWatcher::EnsureProcessTerminated(handle);
|
| - }
|
| -#endif // OS_POSIX
|
| - process.Close();
|
| - }
|
| -
|
| - Client* client_;
|
| - ChromeThread::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();
|
| -}
|
| -
|
| -bool ChildProcessLauncher::DidProcessCrash() {
|
| - bool did_crash, child_exited;
|
| - base::ProcessHandle handle = context_->process_.handle();
|
| -#if defined(OS_LINUX)
|
| - if (context_->zygote_) {
|
| - did_crash = Singleton<ZygoteHost>()->DidProcessCrash(handle, &child_exited);
|
| - } else
|
| -#endif
|
| - {
|
| - did_crash = base::DidProcessCrash(&child_exited, handle);
|
| - }
|
| -
|
| - // 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
|
| - // DidProcessCrash called waitpid with WNOHANG, it'll reap the process.
|
| - // However, if DidProcessCrash didn't reap the child, we'll need to in
|
| - // Terminate via ProcessWatcher. So we can't close the handle here.
|
| - if (child_exited)
|
| - context_->process_.Close();
|
| -
|
| - return did_crash;
|
| -}
|
| -
|
| -void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
|
| - DCHECK(!context_->starting_);
|
| - context_->process_.SetProcessBackgrounded(background);
|
| -}
|
|
|