| Index: content/browser/child_process_launcher_helper.cc
|
| diff --git a/content/browser/child_process_launcher_helper.cc b/content/browser/child_process_launcher_helper.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9aa83459ba904dbf4e7db6a08f125a156cdda4a9
|
| --- /dev/null
|
| +++ b/content/browser/child_process_launcher_helper.cc
|
| @@ -0,0 +1,165 @@
|
| +// Copyright 2017 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 "content/browser/child_process_launcher_helper.h"
|
| +
|
| +#include "base/metrics/histogram_macros.h"
|
| +#include "content/browser/child_process_launcher.h"
|
| +#include "content/public/common/content_switches.h"
|
| +#include "content/public/common/sandboxed_process_launcher_delegate.h"
|
| +#include "mojo/edk/embedder/platform_channel_pair.h"
|
| +
|
| +namespace content {
|
| +namespace internal {
|
| +
|
| +namespace {
|
| +
|
| +void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
|
| + // Log the launch time, separating out the first one (which will likely be
|
| + // slower due to the rest of the browser initializing at the same time).
|
| + static bool done_first_launch = false;
|
| + if (done_first_launch) {
|
| + UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
|
| + } else {
|
| + UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
|
| + done_first_launch = true;
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ChildProcessLauncherHelper::Process::Process(Process&& other)
|
| + : process(std::move(other.process))
|
| +#if defined(OS_LINUX)
|
| + , zygote(other.zygote)
|
| +#endif
|
| +{
|
| +}
|
| +
|
| +ChildProcessLauncherHelper::Process&
|
| +ChildProcessLauncherHelper::Process::Process::operator=(
|
| + ChildProcessLauncherHelper::Process&& other) {
|
| + DCHECK_NE(this, &other);
|
| + process = std::move(other.process);
|
| +#if defined(OS_LINUX)
|
| + zygote = other.zygote;
|
| +#endif
|
| + return *this;
|
| +}
|
| +
|
| +ChildProcessLauncherHelper::ChildProcessLauncherHelper(
|
| + int child_process_id,
|
| + BrowserThread::ID client_thread_id,
|
| + std::unique_ptr<base::CommandLine> command_line,
|
| + std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
|
| + const base::WeakPtr<ChildProcessLauncher>& child_process_launcher,
|
| + bool terminate_on_shutdown)
|
| + : child_process_id_(child_process_id),
|
| + client_thread_id_(client_thread_id),
|
| + command_line_(std::move(command_line)),
|
| + delegate_(std::move(delegate)),
|
| + child_process_launcher_(child_process_launcher),
|
| + terminate_on_shutdown_(terminate_on_shutdown) {
|
| +}
|
| +
|
| +ChildProcessLauncherHelper::~ChildProcessLauncherHelper() {
|
| +}
|
| +
|
| +void ChildProcessLauncherHelper::StartLaunchOnClientThread() {
|
| + DCHECK_CURRENTLY_ON(client_thread_id_);
|
| +
|
| + BeforeLaunchOnClientThread();
|
| +
|
| + mojo_server_handle_ = PrepareMojoPipeHandlesOnClientThread();
|
| + if (!mojo_server_handle_.is_valid()) {
|
| + mojo::edk::PlatformChannelPair channel_pair;
|
| + mojo_server_handle_ = channel_pair.PassServerHandle();
|
| + mojo_client_handle_ = channel_pair.PassClientHandle();
|
| + }
|
| +
|
| + BrowserThread::PostTask(
|
| + BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
|
| + base::Bind(&ChildProcessLauncherHelper::LaunchOnLauncherThread, this));
|
| +}
|
| +
|
| +void ChildProcessLauncherHelper::LaunchOnLauncherThread() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
|
| +
|
| + begin_launch_time_ = base::TimeTicks::Now();
|
| +
|
| + std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap();
|
| +
|
| + bool is_synchronous_launch = true;
|
| + int launch_result = LAUNCH_RESULT_FAILURE;
|
| + base::LaunchOptions options;
|
| + BeforeLaunchOnLauncherThread(*files_to_register, &options);
|
| +
|
| + Process process = LaunchProcessOnLauncherThread(options,
|
| + std::move(files_to_register),
|
| + &is_synchronous_launch,
|
| + &launch_result);
|
| +
|
| + AfterLaunchOnLauncherThread(process, options);
|
| +
|
| + if (is_synchronous_launch) {
|
| + PostLaunchOnLauncherThread(std::move(process), launch_result, false);
|
| + }
|
| +}
|
| +
|
| +void ChildProcessLauncherHelper::PostLaunchOnLauncherThread(
|
| + ChildProcessLauncherHelper::Process process,
|
| + int launch_result,
|
| + bool post_launch_on_client_thread_called) {
|
| + // Release the client handle now that the process has been started (the pipe
|
| + // may not signal when the process dies otherwise and we would not detect the
|
| + // child process died).
|
| + mojo_client_handle_.reset();
|
| +
|
| + if (process.process.IsValid()) {
|
| + RecordHistogramsOnLauncherThread(
|
| + base::TimeTicks::Now() - begin_launch_time_);
|
| + }
|
| +
|
| + if (!post_launch_on_client_thread_called) {
|
| + BrowserThread::PostTask(
|
| + client_thread_id_, FROM_HERE,
|
| + base::Bind(&ChildProcessLauncherHelper::PostLaunchOnClientThread,
|
| + this, base::Passed(&process), launch_result));
|
| + }
|
| +}
|
| +
|
| +void ChildProcessLauncherHelper::PostLaunchOnClientThread(
|
| + ChildProcessLauncherHelper::Process process,
|
| + int error_code) {
|
| + if (child_process_launcher_) {
|
| + child_process_launcher_->Notify(
|
| + std::move(process), std::move(mojo_server_handle_), error_code);
|
| + } else if (process.process.IsValid() && terminate_on_shutdown_) {
|
| + // Client is gone, terminate the process.
|
| + ForceNormalProcessTerminationAsync(std::move(process));
|
| + }
|
| +}
|
| +
|
| +std::string ChildProcessLauncherHelper::GetProcessType() {
|
| + return command_line()->GetSwitchValueASCII(switches::kProcessType);
|
| +}
|
| +
|
| +// static
|
| +void ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
|
| + ChildProcessLauncherHelper::Process process) {
|
| + if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
|
| + ForceNormalProcessTerminationSync(std::move(process));
|
| + return;
|
| + }
|
| + // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!
|
| + // So don't do this on the UI/IO threads.
|
| + BrowserThread::PostTask(
|
| + BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
|
| + base::Bind(&ChildProcessLauncherHelper::ForceNormalProcessTerminationSync,
|
| + base::Passed(&process)));
|
| +}
|
| +
|
| +} // namespace internal
|
| +} // namespace content
|
|
|