blob: 68ae99ed8e54edc5954f76b02101958a4b5762a5 [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"
Xi Han89d93df2018-03-09 20:55:079#include "base/no_destructor.h"
10#include "base/single_thread_task_runner.h"
Xi Han9340143c2018-03-16 20:50:4911#include "base/task_scheduler/lazy_task_runner.h"
Xi Han89d93df2018-03-09 20:55:0712#include "base/task_scheduler/post_task.h"
13#include "base/task_scheduler/single_thread_task_runner_thread_mode.h"
14#include "base/task_scheduler/task_traits.h"
jcivelli828cd7f2017-01-18 19:50:4615#include "content/browser/child_process_launcher.h"
Xi Han89d93df2018-03-09 20:55:0716#include "content/public/browser/child_process_launcher_utils.h"
jcivelli828cd7f2017-01-18 19:50:4617#include "content/public/common/content_switches.h"
18#include "content/public/common/sandboxed_process_launcher_delegate.h"
Ken Rockot026afc32018-06-04 19:19:1819#include "mojo/public/cpp/platform/platform_channel.h"
jcivelli828cd7f2017-01-18 19:50:4620
Xi Han89d93df2018-03-09 20:55:0721#if defined(OS_ANDROID)
22#include "content/browser/android/launcher_thread.h"
23#endif
24
jcivelli828cd7f2017-01-18 19:50:4625namespace content {
26namespace internal {
27
28namespace {
29
30void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
Xi Han89d93df2018-03-09 20:55:0731 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
jcivelli828cd7f2017-01-18 19:50:4632 // Log the launch time, separating out the first one (which will likely be
33 // slower due to the rest of the browser initializing at the same time).
34 static bool done_first_launch = false;
35 if (done_first_launch) {
36 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
37 } else {
38 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
39 done_first_launch = true;
40 }
41}
42
43} // namespace
44
45ChildProcessLauncherHelper::Process::Process(Process&& other)
Tom Sepez006b8152018-01-17 20:45:0146 : process(std::move(other.process))
47#if BUILDFLAG(USE_ZYGOTE_HANDLE)
48 ,
49 zygote(other.zygote)
jcivelli828cd7f2017-01-18 19:50:4650#endif
51{
52}
53
54ChildProcessLauncherHelper::Process&
55ChildProcessLauncherHelper::Process::Process::operator=(
56 ChildProcessLauncherHelper::Process&& other) {
57 DCHECK_NE(this, &other);
58 process = std::move(other.process);
Tom Sepez006b8152018-01-17 20:45:0159#if BUILDFLAG(USE_ZYGOTE_HANDLE)
jcivelli828cd7f2017-01-18 19:50:4660 zygote = other.zygote;
61#endif
62 return *this;
63}
64
65ChildProcessLauncherHelper::ChildProcessLauncherHelper(
66 int child_process_id,
67 BrowserThread::ID client_thread_id,
68 std::unique_ptr<base::CommandLine> command_line,
69 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
70 const base::WeakPtr<ChildProcessLauncher>& child_process_launcher,
Dmitry Skiba1b7dbaf82017-11-09 19:32:0271 bool terminate_on_shutdown,
Ken Rockot026afc32018-06-04 19:19:1872 mojo::OutgoingInvitation mojo_invitation,
73 const mojo::ProcessErrorCallback& process_error_callback)
jcivelli828cd7f2017-01-18 19:50:4674 : child_process_id_(child_process_id),
75 client_thread_id_(client_thread_id),
76 command_line_(std::move(command_line)),
77 delegate_(std::move(delegate)),
78 child_process_launcher_(child_process_launcher),
Dmitry Skiba1b7dbaf82017-11-09 19:32:0279 terminate_on_shutdown_(terminate_on_shutdown),
Ken Rockot026afc32018-06-04 19:19:1880 mojo_invitation_(std::move(mojo_invitation)),
Dmitry Skiba1b7dbaf82017-11-09 19:32:0281 process_error_callback_(process_error_callback) {}
jcivelli828cd7f2017-01-18 19:50:4682
Ken Rockot026afc32018-06-04 19:19:1883ChildProcessLauncherHelper::~ChildProcessLauncherHelper() = default;
jcivelli828cd7f2017-01-18 19:50:4684
85void ChildProcessLauncherHelper::StartLaunchOnClientThread() {
86 DCHECK_CURRENTLY_ON(client_thread_id_);
87
88 BeforeLaunchOnClientThread();
89
Ken Rockot026afc32018-06-04 19:19:1890 mojo_named_channel_ = CreateNamedPlatformChannelOnClientThread();
91 if (!mojo_named_channel_)
92 mojo_channel_.emplace();
jcivelli828cd7f2017-01-18 19:50:4693
Xi Han89d93df2018-03-09 20:55:0794 GetProcessLauncherTaskRunner()->PostTask(
95 FROM_HERE,
tzik4fea24af2017-08-23 11:41:4796 base::BindOnce(&ChildProcessLauncherHelper::LaunchOnLauncherThread,
97 this));
jcivelli828cd7f2017-01-18 19:50:4698}
99
100void ChildProcessLauncherHelper::LaunchOnLauncherThread() {
Xi Han89d93df2018-03-09 20:55:07101 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
jcivelli828cd7f2017-01-18 19:50:46102
103 begin_launch_time_ = base::TimeTicks::Now();
104
105 std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap();
106
107 bool is_synchronous_launch = true;
108 int launch_result = LAUNCH_RESULT_FAILURE;
109 base::LaunchOptions options;
jcivelli828cd7f2017-01-18 19:50:46110
Greg Kerra1bc9d02018-01-04 23:22:31111 Process process;
112 if (BeforeLaunchOnLauncherThread(*files_to_register, &options)) {
113 process =
114 LaunchProcessOnLauncherThread(options, std::move(files_to_register),
115 &is_synchronous_launch, &launch_result);
jcivelli828cd7f2017-01-18 19:50:46116
Greg Kerra1bc9d02018-01-04 23:22:31117 AfterLaunchOnLauncherThread(process, options);
118 }
jcivelli828cd7f2017-01-18 19:50:46119
120 if (is_synchronous_launch) {
boliu5674fee2017-04-26 23:41:59121 PostLaunchOnLauncherThread(std::move(process), launch_result);
jcivelli828cd7f2017-01-18 19:50:46122 }
123}
124
125void ChildProcessLauncherHelper::PostLaunchOnLauncherThread(
126 ChildProcessLauncherHelper::Process process,
boliu5674fee2017-04-26 23:41:59127 int launch_result) {
Ken Rockot026afc32018-06-04 19:19:18128 if (mojo_channel_)
129 mojo_channel_->RemoteProcessLaunched();
jcivelli828cd7f2017-01-18 19:50:46130
131 if (process.process.IsValid()) {
boliu5674fee2017-04-26 23:41:59132 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
133 begin_launch_time_);
jcivelli828cd7f2017-01-18 19:50:46134 }
135
Dmitry Skiba1b7dbaf82017-11-09 19:32:02136 // Take ownership of the broker client invitation here so it's destroyed when
137 // we go out of scope regardless of the outcome below.
Ken Rockot026afc32018-06-04 19:19:18138 mojo::OutgoingInvitation invitation = std::move(mojo_invitation_);
Dmitry Skiba1b7dbaf82017-11-09 19:32:02139 if (process.process.IsValid()) {
140 // Set up Mojo IPC to the new process.
Ken Rockot026afc32018-06-04 19:19:18141 if (mojo_channel_) {
142 DCHECK(mojo_channel_->local_endpoint().is_valid());
143 mojo::OutgoingInvitation::Send(
144 std::move(invitation), process.process.Handle(),
145 mojo_channel_->TakeLocalEndpoint(), process_error_callback_);
146 } else {
147 DCHECK(mojo_named_channel_);
148 mojo::OutgoingInvitation::Send(
149 std::move(invitation), process.process.Handle(),
150 mojo_named_channel_->TakeServerEndpoint(), process_error_callback_);
151 }
Dmitry Skiba1b7dbaf82017-11-09 19:32:02152 }
153
boliu5674fee2017-04-26 23:41:59154 BrowserThread::PostTask(
155 client_thread_id_, FROM_HERE,
tzik4fea24af2017-08-23 11:41:47156 base::BindOnce(&ChildProcessLauncherHelper::PostLaunchOnClientThread,
tzikccf160c2018-02-20 12:43:13157 this, std::move(process), launch_result));
jcivelli828cd7f2017-01-18 19:50:46158}
159
160void ChildProcessLauncherHelper::PostLaunchOnClientThread(
161 ChildProcessLauncherHelper::Process process,
162 int error_code) {
163 if (child_process_launcher_) {
Dmitry Skiba1b7dbaf82017-11-09 19:32:02164 child_process_launcher_->Notify(std::move(process), error_code);
jcivelli828cd7f2017-01-18 19:50:46165 } else if (process.process.IsValid() && terminate_on_shutdown_) {
166 // Client is gone, terminate the process.
167 ForceNormalProcessTerminationAsync(std::move(process));
168 }
169}
170
171std::string ChildProcessLauncherHelper::GetProcessType() {
172 return command_line()->GetSwitchValueASCII(switches::kProcessType);
173}
174
175// static
176void ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
177 ChildProcessLauncherHelper::Process process) {
Xi Han89d93df2018-03-09 20:55:07178 if (CurrentlyOnProcessLauncherTaskRunner()) {
jcivelli828cd7f2017-01-18 19:50:46179 ForceNormalProcessTerminationSync(std::move(process));
180 return;
181 }
182 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!
183 // So don't do this on the UI/IO threads.
Xi Han89d93df2018-03-09 20:55:07184 GetProcessLauncherTaskRunner()->PostTask(
185 FROM_HERE,
tzik4fea24af2017-08-23 11:41:47186 base::BindOnce(
187 &ChildProcessLauncherHelper::ForceNormalProcessTerminationSync,
tzikccf160c2018-02-20 12:43:13188 std::move(process)));
jcivelli828cd7f2017-01-18 19:50:46189}
190
191} // namespace internal
Xi Han89d93df2018-03-09 20:55:07192
193// static
194base::SingleThreadTaskRunner* GetProcessLauncherTaskRunner() {
195#if defined(OS_ANDROID)
196 // Android specializes Launcher thread so it is accessible in java.
197 // Note Android never does clean shutdown, so shutdown use-after-free
198 // concerns are not a problem in practice.
199 // This process launcher thread will use the Java-side process-launching
200 // thread, instead of creating its own separate thread on C++ side. Note
201 // that means this thread will not be joined on shutdown, and may cause
202 // use-after-free if anything tries to access objects deleted by
203 // AtExitManager, such as non-leaky LazyInstance.
204 static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>>
205 launcher_task_runner(
206 android::LauncherThread::GetMessageLoop()->task_runner());
Xi Han89d93df2018-03-09 20:55:07207 return (*launcher_task_runner).get();
Sunny Sachanandanic16fdeb2018-04-25 00:25:48208#else // defined(OS_ANDROID)
209 // TODO(http://crbug.com/820200): Investigate whether we could use
210 // SequencedTaskRunner on platforms other than Windows.
Xi Han9340143c2018-03-16 20:50:49211 static base::LazySingleThreadTaskRunner launcher_task_runner =
212 LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
213 base::TaskTraits({base::MayBlock(), base::TaskPriority::USER_BLOCKING,
Sunny Sachanandanic16fdeb2018-04-25 00:25:48214 base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
Xi Han9340143c2018-03-16 20:50:49215 base::SingleThreadTaskRunnerThreadMode::DEDICATED);
216 return launcher_task_runner.Get().get();
217#endif // defined(OS_ANDROID)
Xi Han89d93df2018-03-09 20:55:07218}
219
220// static
221bool CurrentlyOnProcessLauncherTaskRunner() {
222 return GetProcessLauncherTaskRunner()->RunsTasksInCurrentSequence();
223}
224
jcivelli828cd7f2017-01-18 19:50:46225} // namespace content