blob: 7b5ce4eae650210f248d84dadd573fde5bb22315 [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
Ken Rockot86bea1c2017-05-16 06:21:357#include "base/command_line.h"
jcivelli828cd7f2017-01-18 19:50:468#include "base/metrics/histogram_macros.h"
9#include "content/browser/child_process_launcher.h"
10#include "content/public/common/content_switches.h"
11#include "content/public/common/sandboxed_process_launcher_delegate.h"
12#include "mojo/edk/embedder/platform_channel_pair.h"
13
14namespace content {
15namespace internal {
16
17namespace {
18
19void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
20 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
21 // Log the launch time, separating out the first one (which will likely be
22 // slower due to the rest of the browser initializing at the same time).
23 static bool done_first_launch = false;
24 if (done_first_launch) {
25 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
26 } else {
27 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
28 done_first_launch = true;
29 }
30}
31
32} // namespace
33
34ChildProcessLauncherHelper::Process::Process(Process&& other)
35 : process(std::move(other.process))
36#if defined(OS_LINUX)
37 , zygote(other.zygote)
38#endif
39{
40}
41
42ChildProcessLauncherHelper::Process&
43ChildProcessLauncherHelper::Process::Process::operator=(
44 ChildProcessLauncherHelper::Process&& other) {
45 DCHECK_NE(this, &other);
46 process = std::move(other.process);
47#if defined(OS_LINUX)
48 zygote = other.zygote;
49#endif
50 return *this;
51}
52
53ChildProcessLauncherHelper::ChildProcessLauncherHelper(
54 int child_process_id,
55 BrowserThread::ID client_thread_id,
56 std::unique_ptr<base::CommandLine> command_line,
57 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
58 const base::WeakPtr<ChildProcessLauncher>& child_process_launcher,
59 bool terminate_on_shutdown)
60 : child_process_id_(child_process_id),
61 client_thread_id_(client_thread_id),
62 command_line_(std::move(command_line)),
63 delegate_(std::move(delegate)),
64 child_process_launcher_(child_process_launcher),
65 terminate_on_shutdown_(terminate_on_shutdown) {
66}
67
68ChildProcessLauncherHelper::~ChildProcessLauncherHelper() {
69}
70
71void ChildProcessLauncherHelper::StartLaunchOnClientThread() {
72 DCHECK_CURRENTLY_ON(client_thread_id_);
73
74 BeforeLaunchOnClientThread();
75
76 mojo_server_handle_ = PrepareMojoPipeHandlesOnClientThread();
77 if (!mojo_server_handle_.is_valid()) {
78 mojo::edk::PlatformChannelPair channel_pair;
79 mojo_server_handle_ = channel_pair.PassServerHandle();
80 mojo_client_handle_ = channel_pair.PassClientHandle();
81 }
82
83 BrowserThread::PostTask(
84 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
tzik4fea24af2017-08-23 11:41:4785 base::BindOnce(&ChildProcessLauncherHelper::LaunchOnLauncherThread,
86 this));
jcivelli828cd7f2017-01-18 19:50:4687}
88
89void ChildProcessLauncherHelper::LaunchOnLauncherThread() {
90 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
91
92 begin_launch_time_ = base::TimeTicks::Now();
93
94 std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap();
95
96 bool is_synchronous_launch = true;
97 int launch_result = LAUNCH_RESULT_FAILURE;
98 base::LaunchOptions options;
99 BeforeLaunchOnLauncherThread(*files_to_register, &options);
100
101 Process process = LaunchProcessOnLauncherThread(options,
102 std::move(files_to_register),
103 &is_synchronous_launch,
104 &launch_result);
105
106 AfterLaunchOnLauncherThread(process, options);
107
108 if (is_synchronous_launch) {
boliu5674fee2017-04-26 23:41:59109 PostLaunchOnLauncherThread(std::move(process), launch_result);
jcivelli828cd7f2017-01-18 19:50:46110 }
111}
112
113void ChildProcessLauncherHelper::PostLaunchOnLauncherThread(
114 ChildProcessLauncherHelper::Process process,
boliu5674fee2017-04-26 23:41:59115 int launch_result) {
jcivelli828cd7f2017-01-18 19:50:46116 // Release the client handle now that the process has been started (the pipe
117 // may not signal when the process dies otherwise and we would not detect the
118 // child process died).
119 mojo_client_handle_.reset();
120
121 if (process.process.IsValid()) {
boliu5674fee2017-04-26 23:41:59122 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
123 begin_launch_time_);
jcivelli828cd7f2017-01-18 19:50:46124 }
125
boliu5674fee2017-04-26 23:41:59126 BrowserThread::PostTask(
127 client_thread_id_, FROM_HERE,
tzik4fea24af2017-08-23 11:41:47128 base::BindOnce(&ChildProcessLauncherHelper::PostLaunchOnClientThread,
129 this, base::Passed(&process), launch_result));
jcivelli828cd7f2017-01-18 19:50:46130}
131
132void ChildProcessLauncherHelper::PostLaunchOnClientThread(
133 ChildProcessLauncherHelper::Process process,
134 int error_code) {
135 if (child_process_launcher_) {
136 child_process_launcher_->Notify(
137 std::move(process), std::move(mojo_server_handle_), error_code);
138 } else if (process.process.IsValid() && terminate_on_shutdown_) {
139 // Client is gone, terminate the process.
140 ForceNormalProcessTerminationAsync(std::move(process));
141 }
142}
143
144std::string ChildProcessLauncherHelper::GetProcessType() {
145 return command_line()->GetSwitchValueASCII(switches::kProcessType);
146}
147
148// static
149void ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
150 ChildProcessLauncherHelper::Process process) {
151 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
152 ForceNormalProcessTerminationSync(std::move(process));
153 return;
154 }
155 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!
156 // So don't do this on the UI/IO threads.
157 BrowserThread::PostTask(
158 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
tzik4fea24af2017-08-23 11:41:47159 base::BindOnce(
160 &ChildProcessLauncherHelper::ForceNormalProcessTerminationSync,
161 base::Passed(&process)));
jcivelli828cd7f2017-01-18 19:50:46162}
163
164} // namespace internal
165} // namespace content