blob: 2f75fff5eed4dada724818e9330f3a46c42699d7 [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"
Gabriel Charette44db1422018-08-06 11:19:3311#include "base/task/lazy_task_runner.h"
12#include "base/task/post_task.h"
13#include "base/task/single_thread_task_runner_thread_mode.h"
14#include "base/task/task_traits.h"
jcivelli828cd7f2017-01-18 19:50:4615#include "content/browser/child_process_launcher.h"
Eric Seckler8652dcd52018-09-20 10:42:2816#include "content/public/browser/browser_task_traits.h"
Xi Han89d93df2018-03-09 20:55:0717#include "content/public/browser/child_process_launcher_utils.h"
jcivelli828cd7f2017-01-18 19:50:4618#include "content/public/common/content_switches.h"
19#include "content/public/common/sandboxed_process_launcher_delegate.h"
Ken Rockot026afc32018-06-04 19:19:1820#include "mojo/public/cpp/platform/platform_channel.h"
jcivelli828cd7f2017-01-18 19:50:4621
Xi Han89d93df2018-03-09 20:55:0722#if defined(OS_ANDROID)
23#include "content/browser/android/launcher_thread.h"
24#endif
25
jcivelli828cd7f2017-01-18 19:50:4626namespace content {
27namespace internal {
28
29namespace {
30
31void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
Xi Han89d93df2018-03-09 20:55:0732 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
jcivelli828cd7f2017-01-18 19:50:4633 // Log the launch time, separating out the first one (which will likely be
34 // slower due to the rest of the browser initializing at the same time).
35 static bool done_first_launch = false;
36 if (done_first_launch) {
37 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
38 } else {
39 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
40 done_first_launch = true;
41 }
42}
43
44} // namespace
45
46ChildProcessLauncherHelper::Process::Process(Process&& other)
Tom Sepez006b8152018-01-17 20:45:0147 : process(std::move(other.process))
48#if BUILDFLAG(USE_ZYGOTE_HANDLE)
49 ,
50 zygote(other.zygote)
jcivelli828cd7f2017-01-18 19:50:4651#endif
52{
53}
54
55ChildProcessLauncherHelper::Process&
56ChildProcessLauncherHelper::Process::Process::operator=(
57 ChildProcessLauncherHelper::Process&& other) {
58 DCHECK_NE(this, &other);
59 process = std::move(other.process);
Tom Sepez006b8152018-01-17 20:45:0160#if BUILDFLAG(USE_ZYGOTE_HANDLE)
jcivelli828cd7f2017-01-18 19:50:4661 zygote = other.zygote;
62#endif
63 return *this;
64}
65
66ChildProcessLauncherHelper::ChildProcessLauncherHelper(
67 int child_process_id,
68 BrowserThread::ID client_thread_id,
69 std::unique_ptr<base::CommandLine> command_line,
70 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
71 const base::WeakPtr<ChildProcessLauncher>& child_process_launcher,
Dmitry Skiba1b7dbaf82017-11-09 19:32:0272 bool terminate_on_shutdown,
Ken Rockot026afc32018-06-04 19:19:1873 mojo::OutgoingInvitation mojo_invitation,
74 const mojo::ProcessErrorCallback& process_error_callback)
jcivelli828cd7f2017-01-18 19:50:4675 : child_process_id_(child_process_id),
76 client_thread_id_(client_thread_id),
77 command_line_(std::move(command_line)),
78 delegate_(std::move(delegate)),
79 child_process_launcher_(child_process_launcher),
Dmitry Skiba1b7dbaf82017-11-09 19:32:0280 terminate_on_shutdown_(terminate_on_shutdown),
Ken Rockot026afc32018-06-04 19:19:1881 mojo_invitation_(std::move(mojo_invitation)),
Dmitry Skiba1b7dbaf82017-11-09 19:32:0282 process_error_callback_(process_error_callback) {}
jcivelli828cd7f2017-01-18 19:50:4683
Ken Rockot026afc32018-06-04 19:19:1884ChildProcessLauncherHelper::~ChildProcessLauncherHelper() = default;
jcivelli828cd7f2017-01-18 19:50:4685
86void ChildProcessLauncherHelper::StartLaunchOnClientThread() {
87 DCHECK_CURRENTLY_ON(client_thread_id_);
88
89 BeforeLaunchOnClientThread();
90
Ken Rockot026afc32018-06-04 19:19:1891 mojo_named_channel_ = CreateNamedPlatformChannelOnClientThread();
92 if (!mojo_named_channel_)
93 mojo_channel_.emplace();
jcivelli828cd7f2017-01-18 19:50:4694
Xi Han89d93df2018-03-09 20:55:0795 GetProcessLauncherTaskRunner()->PostTask(
96 FROM_HERE,
tzik4fea24af2017-08-23 11:41:4797 base::BindOnce(&ChildProcessLauncherHelper::LaunchOnLauncherThread,
98 this));
jcivelli828cd7f2017-01-18 19:50:4699}
100
101void ChildProcessLauncherHelper::LaunchOnLauncherThread() {
Xi Han89d93df2018-03-09 20:55:07102 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
jcivelli828cd7f2017-01-18 19:50:46103
104 begin_launch_time_ = base::TimeTicks::Now();
105
106 std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap();
107
108 bool is_synchronous_launch = true;
109 int launch_result = LAUNCH_RESULT_FAILURE;
110 base::LaunchOptions options;
jcivelli828cd7f2017-01-18 19:50:46111
Greg Kerra1bc9d02018-01-04 23:22:31112 Process process;
113 if (BeforeLaunchOnLauncherThread(*files_to_register, &options)) {
114 process =
115 LaunchProcessOnLauncherThread(options, std::move(files_to_register),
116 &is_synchronous_launch, &launch_result);
jcivelli828cd7f2017-01-18 19:50:46117
Greg Kerra1bc9d02018-01-04 23:22:31118 AfterLaunchOnLauncherThread(process, options);
119 }
jcivelli828cd7f2017-01-18 19:50:46120
121 if (is_synchronous_launch) {
boliu5674fee2017-04-26 23:41:59122 PostLaunchOnLauncherThread(std::move(process), launch_result);
jcivelli828cd7f2017-01-18 19:50:46123 }
124}
125
126void ChildProcessLauncherHelper::PostLaunchOnLauncherThread(
127 ChildProcessLauncherHelper::Process process,
boliu5674fee2017-04-26 23:41:59128 int launch_result) {
Ken Rockot026afc32018-06-04 19:19:18129 if (mojo_channel_)
Wezdc98dbfd2018-06-05 19:49:42130 mojo_channel_->RemoteProcessLaunchAttempted();
jcivelli828cd7f2017-01-18 19:50:46131
132 if (process.process.IsValid()) {
boliu5674fee2017-04-26 23:41:59133 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
134 begin_launch_time_);
jcivelli828cd7f2017-01-18 19:50:46135 }
136
Dmitry Skiba1b7dbaf82017-11-09 19:32:02137 // Take ownership of the broker client invitation here so it's destroyed when
138 // we go out of scope regardless of the outcome below.
Ken Rockot026afc32018-06-04 19:19:18139 mojo::OutgoingInvitation invitation = std::move(mojo_invitation_);
Dmitry Skiba1b7dbaf82017-11-09 19:32:02140 if (process.process.IsValid()) {
141 // Set up Mojo IPC to the new process.
Ken Rockot026afc32018-06-04 19:19:18142 if (mojo_channel_) {
143 DCHECK(mojo_channel_->local_endpoint().is_valid());
144 mojo::OutgoingInvitation::Send(
145 std::move(invitation), process.process.Handle(),
146 mojo_channel_->TakeLocalEndpoint(), process_error_callback_);
147 } else {
148 DCHECK(mojo_named_channel_);
149 mojo::OutgoingInvitation::Send(
150 std::move(invitation), process.process.Handle(),
151 mojo_named_channel_->TakeServerEndpoint(), process_error_callback_);
152 }
Dmitry Skiba1b7dbaf82017-11-09 19:32:02153 }
154
Eric Seckler8652dcd52018-09-20 10:42:28155 base::PostTaskWithTraits(
156 FROM_HERE, {client_thread_id_},
tzik4fea24af2017-08-23 11:41:47157 base::BindOnce(&ChildProcessLauncherHelper::PostLaunchOnClientThread,
tzikccf160c2018-02-20 12:43:13158 this, std::move(process), launch_result));
jcivelli828cd7f2017-01-18 19:50:46159}
160
161void ChildProcessLauncherHelper::PostLaunchOnClientThread(
162 ChildProcessLauncherHelper::Process process,
163 int error_code) {
164 if (child_process_launcher_) {
Dmitry Skiba1b7dbaf82017-11-09 19:32:02165 child_process_launcher_->Notify(std::move(process), error_code);
jcivelli828cd7f2017-01-18 19:50:46166 } else if (process.process.IsValid() && terminate_on_shutdown_) {
167 // Client is gone, terminate the process.
168 ForceNormalProcessTerminationAsync(std::move(process));
169 }
170}
171
172std::string ChildProcessLauncherHelper::GetProcessType() {
173 return command_line()->GetSwitchValueASCII(switches::kProcessType);
174}
175
176// static
177void ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
178 ChildProcessLauncherHelper::Process process) {
Xi Han89d93df2018-03-09 20:55:07179 if (CurrentlyOnProcessLauncherTaskRunner()) {
jcivelli828cd7f2017-01-18 19:50:46180 ForceNormalProcessTerminationSync(std::move(process));
181 return;
182 }
183 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!
184 // So don't do this on the UI/IO threads.
Xi Han89d93df2018-03-09 20:55:07185 GetProcessLauncherTaskRunner()->PostTask(
186 FROM_HERE,
tzik4fea24af2017-08-23 11:41:47187 base::BindOnce(
188 &ChildProcessLauncherHelper::ForceNormalProcessTerminationSync,
tzikccf160c2018-02-20 12:43:13189 std::move(process)));
jcivelli828cd7f2017-01-18 19:50:46190}
191
192} // namespace internal
Xi Han89d93df2018-03-09 20:55:07193
194// static
195base::SingleThreadTaskRunner* GetProcessLauncherTaskRunner() {
196#if defined(OS_ANDROID)
197 // Android specializes Launcher thread so it is accessible in java.
198 // Note Android never does clean shutdown, so shutdown use-after-free
199 // concerns are not a problem in practice.
200 // This process launcher thread will use the Java-side process-launching
201 // thread, instead of creating its own separate thread on C++ side. Note
202 // that means this thread will not be joined on shutdown, and may cause
203 // use-after-free if anything tries to access objects deleted by
204 // AtExitManager, such as non-leaky LazyInstance.
205 static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>>
206 launcher_task_runner(
207 android::LauncherThread::GetMessageLoop()->task_runner());
Xi Han89d93df2018-03-09 20:55:07208 return (*launcher_task_runner).get();
Sunny Sachanandanic16fdeb2018-04-25 00:25:48209#else // defined(OS_ANDROID)
210 // TODO(http://crbug.com/820200): Investigate whether we could use
211 // SequencedTaskRunner on platforms other than Windows.
Xi Han9340143c2018-03-16 20:50:49212 static base::LazySingleThreadTaskRunner launcher_task_runner =
213 LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
214 base::TaskTraits({base::MayBlock(), base::TaskPriority::USER_BLOCKING,
Sunny Sachanandanic16fdeb2018-04-25 00:25:48215 base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
Xi Han9340143c2018-03-16 20:50:49216 base::SingleThreadTaskRunnerThreadMode::DEDICATED);
217 return launcher_task_runner.Get().get();
218#endif // defined(OS_ANDROID)
Xi Han89d93df2018-03-09 20:55:07219}
220
221// static
222bool CurrentlyOnProcessLauncherTaskRunner() {
223 return GetProcessLauncherTaskRunner()->RunsTasksInCurrentSequence();
224}
225
jcivelli828cd7f2017-01-18 19:50:46226} // namespace content