blob: 5d6e9aa6e64e33da84ae4277b585410413798f7e [file] [log] [blame]
jcivelli828cd7f2017-01-18 19:50:461// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/child_process_launcher_helper.h"
6
7#include "base/metrics/histogram_macros.h"
8#include "content/browser/child_process_launcher.h"
9#include "content/public/common/content_switches.h"
10#include "content/public/common/sandboxed_process_launcher_delegate.h"
11#include "mojo/edk/embedder/platform_channel_pair.h"
12
13namespace content {
14namespace internal {
15
16namespace {
17
18void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
19 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
20 // Log the launch time, separating out the first one (which will likely be
21 // slower due to the rest of the browser initializing at the same time).
22 static bool done_first_launch = false;
23 if (done_first_launch) {
24 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
25 } else {
26 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
27 done_first_launch = true;
28 }
29}
30
31} // namespace
32
33ChildProcessLauncherHelper::Process::Process(Process&& other)
34 : process(std::move(other.process))
35#if defined(OS_LINUX)
36 , zygote(other.zygote)
37#endif
38{
39}
40
41ChildProcessLauncherHelper::Process&
42ChildProcessLauncherHelper::Process::Process::operator=(
43 ChildProcessLauncherHelper::Process&& other) {
44 DCHECK_NE(this, &other);
45 process = std::move(other.process);
46#if defined(OS_LINUX)
47 zygote = other.zygote;
48#endif
49 return *this;
50}
51
52ChildProcessLauncherHelper::ChildProcessLauncherHelper(
53 int child_process_id,
54 BrowserThread::ID client_thread_id,
55 std::unique_ptr<base::CommandLine> command_line,
56 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
57 const base::WeakPtr<ChildProcessLauncher>& child_process_launcher,
58 bool terminate_on_shutdown)
59 : child_process_id_(child_process_id),
60 client_thread_id_(client_thread_id),
61 command_line_(std::move(command_line)),
62 delegate_(std::move(delegate)),
63 child_process_launcher_(child_process_launcher),
64 terminate_on_shutdown_(terminate_on_shutdown) {
65}
66
67ChildProcessLauncherHelper::~ChildProcessLauncherHelper() {
68}
69
70void ChildProcessLauncherHelper::StartLaunchOnClientThread() {
71 DCHECK_CURRENTLY_ON(client_thread_id_);
72
73 BeforeLaunchOnClientThread();
74
75 mojo_server_handle_ = PrepareMojoPipeHandlesOnClientThread();
76 if (!mojo_server_handle_.is_valid()) {
77 mojo::edk::PlatformChannelPair channel_pair;
78 mojo_server_handle_ = channel_pair.PassServerHandle();
79 mojo_client_handle_ = channel_pair.PassClientHandle();
80 }
81
82 BrowserThread::PostTask(
83 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
84 base::Bind(&ChildProcessLauncherHelper::LaunchOnLauncherThread, this));
85}
86
87void ChildProcessLauncherHelper::LaunchOnLauncherThread() {
88 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
89
90 begin_launch_time_ = base::TimeTicks::Now();
91
92 std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap();
93
94 bool is_synchronous_launch = true;
95 int launch_result = LAUNCH_RESULT_FAILURE;
96 base::LaunchOptions options;
97 BeforeLaunchOnLauncherThread(*files_to_register, &options);
98
99 Process process = LaunchProcessOnLauncherThread(options,
100 std::move(files_to_register),
101 &is_synchronous_launch,
102 &launch_result);
103
104 AfterLaunchOnLauncherThread(process, options);
105
106 if (is_synchronous_launch) {
boliu5674fee2017-04-26 23:41:59107 PostLaunchOnLauncherThread(std::move(process), launch_result);
jcivelli828cd7f2017-01-18 19:50:46108 }
109}
110
111void ChildProcessLauncherHelper::PostLaunchOnLauncherThread(
112 ChildProcessLauncherHelper::Process process,
boliu5674fee2017-04-26 23:41:59113 int launch_result) {
jcivelli828cd7f2017-01-18 19:50:46114 // Release the client handle now that the process has been started (the pipe
115 // may not signal when the process dies otherwise and we would not detect the
116 // child process died).
117 mojo_client_handle_.reset();
118
119 if (process.process.IsValid()) {
boliu5674fee2017-04-26 23:41:59120 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
121 begin_launch_time_);
jcivelli828cd7f2017-01-18 19:50:46122 }
123
boliu5674fee2017-04-26 23:41:59124 BrowserThread::PostTask(
125 client_thread_id_, FROM_HERE,
126 base::Bind(&ChildProcessLauncherHelper::PostLaunchOnClientThread, this,
127 base::Passed(&process), launch_result));
jcivelli828cd7f2017-01-18 19:50:46128}
129
130void ChildProcessLauncherHelper::PostLaunchOnClientThread(
131 ChildProcessLauncherHelper::Process process,
132 int error_code) {
133 if (child_process_launcher_) {
134 child_process_launcher_->Notify(
135 std::move(process), std::move(mojo_server_handle_), error_code);
136 } else if (process.process.IsValid() && terminate_on_shutdown_) {
137 // Client is gone, terminate the process.
138 ForceNormalProcessTerminationAsync(std::move(process));
139 }
140}
141
142std::string ChildProcessLauncherHelper::GetProcessType() {
143 return command_line()->GetSwitchValueASCII(switches::kProcessType);
144}
145
146// static
147void ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
148 ChildProcessLauncherHelper::Process process) {
149 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
150 ForceNormalProcessTerminationSync(std::move(process));
151 return;
152 }
153 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!
154 // So don't do this on the UI/IO threads.
155 BrowserThread::PostTask(
156 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
157 base::Bind(&ChildProcessLauncherHelper::ForceNormalProcessTerminationSync,
158 base::Passed(&process)));
159}
160
161} // namespace internal
162} // namespace content