blob: e3add3d00dee28798b3f901c8e687f85f7ee31af [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2012 The Chromium Authors
jam@chromium.org9610ef242009-11-18 02:41:262// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
jam@chromium.orgdf8e899b2011-02-22 22:58:225#include "content/browser/child_process_launcher.h"
jam@chromium.org9610ef242009-11-18 02:41:266
Joe Masonba145282024-03-12 20:18:197#include <optional>
Lukasz Anforowiczb10888092018-05-04 00:50:088#include <utility>
9
Hans Wennborg0917de892020-04-28 20:21:1510#include "base/check_op.h"
Sebastien Marchandbd02bc29e2020-03-11 15:53:3611#include "base/clang_profiling_buildflags.h"
jam@chromium.org9610ef242009-11-18 02:41:2612#include "base/command_line.h"
thestigb7aad54f2014-09-05 18:25:3913#include "base/files/file_util.h"
Avi Drissmanadac21992023-01-11 23:46:3914#include "base/functional/bind.h"
agrievefd2d44ab2015-06-19 04:33:0315#include "base/i18n/icu_util.h"
Roger McFarlanecba0e902024-01-24 17:51:3716#include "base/memory/unsafe_shared_memory_region.h"
rockotb3b0dfa02016-02-26 22:43:2817#include "base/process/launch.h"
Olivier Li344b0d232021-05-10 19:30:1518#include "base/time/time.h"
ssid6bedaa92021-06-16 10:25:2419#include "base/tracing/protos/chrome_track_event.pbzero.h"
Joe Mason550eed62024-03-25 18:07:3120#include "base/types/expected.h"
21#include "base/types/optional_util.h"
avib7348942015-12-25 20:57:1022#include "build/build_config.h"
Lei Zhang8f395da62022-10-05 15:06:2023#include "content/public/browser/browser_thread.h"
Xi Han89d93df2018-03-09 20:55:0724#include "content/public/browser/child_process_launcher_utils.h"
Ben Kellyf4fc4ce02019-02-12 16:10:0125#include "content/public/common/content_features.h"
Sebastien Marchand6a582a02021-06-29 01:52:2326#include "content/public/common/content_switches.h"
aberent@chromium.org121e61382014-03-13 11:35:1527#include "content/public/common/sandboxed_process_launcher_delegate.h"
jam@chromium.orgfb1277e82009-11-21 20:32:3028
Calder Kitagawabf5286652022-09-14 15:38:1929#if BUILDFLAG(IS_ANDROID)
30#include "base/android/child_process_binding_types.h"
31#endif
32
Xiaohan Wang1ecfd002022-01-19 22:33:1033#if BUILDFLAG(IS_MAC)
Olivier Li344b0d232021-05-10 19:30:1534#include "content/browser/child_process_task_port_provider_mac.h"
35#endif
36
jam@chromium.org130757672012-10-24 00:26:1937namespace content {
joi@chromium.org631bb742011-11-02 11:29:3938
Patrick Monette87b033b62022-08-24 20:06:1239namespace {
40
41#if !BUILDFLAG(IS_ANDROID)
42// Returns the cumulative CPU usage for the specified process.
Joe Masonba145282024-03-12 20:18:1943std::optional<base::TimeDelta> GetCPUUsage(base::ProcessHandle process_handle) {
Patrick Monette87b033b62022-08-24 20:06:1244#if BUILDFLAG(IS_MAC)
45 std::unique_ptr<base::ProcessMetrics> process_metrics =
46 base::ProcessMetrics::CreateProcessMetrics(
47 process_handle, ChildProcessTaskPortProvider::GetInstance());
48#else
49 std::unique_ptr<base::ProcessMetrics> process_metrics =
50 base::ProcessMetrics::CreateProcessMetrics(process_handle);
51#endif
Joe Mason550eed62024-03-25 18:07:3152 return base::OptionalFromExpected(process_metrics->GetCumulativeCPUUsage());
Patrick Monette87b033b62022-08-24 20:06:1253}
54#endif // !BUILDFLAG(IS_ANDROID)
55
56} // namespace
57
jcivelli828cd7f2017-01-18 19:50:4658using internal::ChildProcessLauncherHelper;
jam@chromium.org9610ef242009-11-18 02:41:2659
Patrick Monetted54f90e2022-12-13 19:03:5560void RenderProcessPriority::WriteIntoTrace(
Alexander Timin074cd182022-03-23 18:11:2261 perfetto::TracedProto<TraceProto> proto) const {
Patrick Monette5d200fc2024-07-23 20:19:3862 // TODO(pmonette): Migrate is_background() to GetProcessPriority().
ssid6bedaa92021-06-16 10:25:2463 proto->set_is_backgrounded(is_background());
64 proto->set_has_pending_views(boost_for_pending_views);
65
Xiaohan Wang1ecfd002022-01-19 22:33:1066#if BUILDFLAG(IS_ANDROID)
ssid6bedaa92021-06-16 10:25:2467 using PriorityProto = perfetto::protos::pbzero::ChildProcessLauncherPriority;
68 switch (importance) {
69 case ChildProcessImportance::IMPORTANT:
70 proto->set_importance(PriorityProto::IMPORTANCE_IMPORTANT);
71 break;
72 case ChildProcessImportance::NORMAL:
73 proto->set_importance(PriorityProto::IMPORTANCE_NORMAL);
74 break;
75 case ChildProcessImportance::MODERATE:
76 proto->set_importance(PriorityProto::IMPORTANCE_MODERATE);
77 break;
78 }
79#endif
80}
81
Eriko Kurimoto9c83b402022-05-11 02:36:3282ChildProcessLauncherFileData::ChildProcessLauncherFileData() = default;
83
84ChildProcessLauncherFileData::~ChildProcessLauncherFileData() = default;
85
Xiaohan Wang1ecfd002022-01-19 22:33:1086#if BUILDFLAG(IS_ANDROID)
Min Qineb961902019-03-16 08:08:2287bool ChildProcessLauncher::Client::CanUseWarmUpConnection() {
88 return true;
89}
90#endif
91
jam@chromium.orgfb1277e82009-11-21 20:32:3092ChildProcessLauncher::ChildProcessLauncher(
jcivellid20cc0b2016-12-22 03:51:4193 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
jcivelli828cd7f2017-01-18 19:50:4694 std::unique_ptr<base::CommandLine> command_line,
jcivelli@chromium.org40da3e0c2012-10-24 22:03:3895 int child_process_id,
sievers954e37a2015-03-28 01:50:2496 Client* client,
Ken Rockot026afc32018-06-04 19:19:1897 mojo::OutgoingInvitation mojo_invitation,
98 const mojo::ProcessErrorCallback& process_error_callback,
Eriko Kurimoto9c83b402022-05-11 02:36:3299 std::unique_ptr<ChildProcessLauncherFileData> file_data,
Roger McFarlanecba0e902024-01-24 17:51:37100 base::UnsafeSharedMemoryRegion histogram_memory_region,
Etienne Pierre-doray25723fa2024-06-28 14:05:57101 base::ReadOnlySharedMemoryRegion tracing_config_memory_region,
sievers954e37a2015-03-28 01:50:24102 bool terminate_on_shutdown)
103 : client_(client),
sievers954e37a2015-03-28 01:50:24104 starting_(true),
105#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
106 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
Sebastien Marchandbd02bc29e2020-03-11 15:53:36107 defined(UNDEFINED_SANITIZER) || BUILDFLAG(CLANG_PROFILING)
Jeremy Roman3bca4bf2019-07-11 03:41:25108 terminate_child_on_shutdown_(false)
sievers954e37a2015-03-28 01:50:24109#else
Jeremy Roman3bca4bf2019-07-11 03:41:25110 terminate_child_on_shutdown_(terminate_on_shutdown)
sievers954e37a2015-03-28 01:50:24111#endif
Jeremy Roman3bca4bf2019-07-11 03:41:25112{
Lei Zhang8f395da62022-10-05 15:06:20113 DCHECK_CURRENTLY_ON(BrowserThread::UI);
jcivelli828cd7f2017-01-18 19:50:46114
Patrick Monette1c4c4172022-09-14 22:04:31115#if BUILDFLAG(IS_WIN)
116 should_launch_elevated_ = delegate->ShouldLaunchElevated();
117#endif
118
Ken Rockot8e23c3ab2019-08-01 23:39:10119 helper_ = base::MakeRefCounted<ChildProcessLauncherHelper>(
120 child_process_id, std::move(command_line), std::move(delegate),
121 weak_factory_.GetWeakPtr(), terminate_on_shutdown,
Xiaohan Wang1ecfd002022-01-19 22:33:10122#if BUILDFLAG(IS_ANDROID)
Min Qineb961902019-03-16 08:08:22123 client_->CanUseWarmUpConnection(),
124#endif
Roger McFarlanecba0e902024-01-24 17:51:37125 std::move(mojo_invitation), process_error_callback, std::move(file_data),
Etienne Pierre-doray25723fa2024-06-28 14:05:57126 std::move(histogram_memory_region),
127 std::move(tracing_config_memory_region));
jcivelli828cd7f2017-01-18 19:50:46128 helper_->StartLaunchOnClientThread();
jam@chromium.org9610ef242009-11-18 02:41:26129}
130
131ChildProcessLauncher::~ChildProcessLauncher() {
Lei Zhang8f395da62022-10-05 15:06:20132 DCHECK_CURRENTLY_ON(BrowserThread::UI);
jcivelli828cd7f2017-01-18 19:50:46133 if (process_.process.IsValid() && terminate_child_on_shutdown_) {
134 // Client has gone away, so just kill the process.
135 ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
136 std::move(process_));
sievers954e37a2015-03-28 01:50:24137 }
138}
139
Patrick Monetted54f90e2022-12-13 19:03:55140#if BUILDFLAG(IS_ANDROID)
141void ChildProcessLauncher::SetRenderProcessPriority(
142 const RenderProcessPriority& priority) {
Lei Zhang8f395da62022-10-05 15:06:20143 DCHECK_CURRENTLY_ON(BrowserThread::UI);
jcivelli828cd7f2017-01-18 19:50:46144 base::Process to_pass = process_.process.Duplicate();
Xi Han89d93df2018-03-09 20:55:07145 GetProcessLauncherTaskRunner()->PostTask(
146 FROM_HERE,
tzik4fea24af2017-08-23 11:41:47147 base::BindOnce(
Patrick Monetted54f90e2022-12-13 19:03:55148 &ChildProcessLauncherHelper::SetRenderProcessPriorityOnLauncherThread,
tzikccf160c2018-02-20 12:43:13149 helper_, std::move(to_pass), priority));
sievers954e37a2015-03-28 01:50:24150}
Patrick Monetted54f90e2022-12-13 19:03:55151#else // !BUILDFLAG(IS_ANDROID)
Patrick Monette20997a22023-08-07 17:30:17152void ChildProcessLauncher::SetProcessPriority(
153 base::Process::Priority priority) {
Patrick Monetted54f90e2022-12-13 19:03:55154 DCHECK_CURRENTLY_ON(BrowserThread::UI);
155 base::Process to_pass = process_.process.Duplicate();
156 GetProcessLauncherTaskRunner()->PostTask(
157 FROM_HERE,
158 base::BindOnce(
Patrick Monette20997a22023-08-07 17:30:17159 &ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread,
160 helper_, std::move(to_pass), priority));
Patrick Monetted54f90e2022-12-13 19:03:55161}
162#endif // !BUILDFLAG(IS_ANDROID)
sievers954e37a2015-03-28 01:50:24163
Will Harrisdf8fcb42021-12-18 09:21:31164void ChildProcessLauncher::Notify(ChildProcessLauncherHelper::Process process,
Xiaohan Wang1ecfd002022-01-19 22:33:10165#if BUILDFLAG(IS_WIN)
Will Harrisdf8fcb42021-12-18 09:21:31166 DWORD last_error,
167#endif
168 int error_code) {
Lei Zhang8f395da62022-10-05 15:06:20169 DCHECK_CURRENTLY_ON(BrowserThread::UI);
sievers954e37a2015-03-28 01:50:24170 starting_ = false;
danakje3de838f2015-12-03 01:49:40171 process_ = std::move(process);
sievers954e37a2015-03-28 01:50:24172
jcivelli828cd7f2017-01-18 19:50:46173 if (process_.process.IsValid()) {
Olivier Li344b0d232021-05-10 19:30:15174 process_start_time_ = base::TimeTicks::Now();
sievers954e37a2015-03-28 01:50:24175 client_->OnProcessLaunched();
176 } else {
Bo Liu0d2a2322018-04-19 00:18:09177 termination_info_.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
Will Harrisdf8fcb42021-12-18 09:21:31178 termination_info_.exit_code = error_code;
Xiaohan Wang1ecfd002022-01-19 22:33:10179#if BUILDFLAG(IS_WIN)
Will Harrisdf8fcb42021-12-18 09:21:31180 termination_info_.last_error = last_error;
181#endif
rockot1039b822017-02-09 23:19:41182
183 // NOTE: May delete |this|.
wfh3adf87d2016-05-03 23:26:06184 client_->OnProcessLaunchFailed(error_code);
sievers954e37a2015-03-28 01:50:24185 }
jam@chromium.org9610ef242009-11-18 02:41:26186}
187
188bool ChildProcessLauncher::IsStarting() {
Lei Zhang8f395da62022-10-05 15:06:20189 DCHECK_CURRENTLY_ON(BrowserThread::UI);
sievers954e37a2015-03-28 01:50:24190 return starting_;
jam@chromium.org9610ef242009-11-18 02:41:26191}
192
rvargas079d1842014-10-17 22:32:16193const base::Process& ChildProcessLauncher::GetProcess() const {
Lei Zhang8f395da62022-10-05 15:06:20194 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Will Harris56d162c2022-04-12 01:57:51195 DCHECK(!starting_);
jcivelli828cd7f2017-01-18 19:50:46196 return process_.process;
jam@chromium.org9610ef242009-11-18 02:41:26197}
198
Bo Liu0d2a2322018-04-19 00:18:09199ChildProcessTerminationInfo ChildProcessLauncher::GetChildTerminationInfo(
200 bool known_dead) {
Lei Zhang8f395da62022-10-05 15:06:20201 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Lukasz Anforowicz2e7a0ea2018-04-09 21:21:06202
jcivelli828cd7f2017-01-18 19:50:46203 if (!process_.process.IsValid()) {
Lukasz Anforowicz2e7a0ea2018-04-09 21:21:06204 // Make sure to avoid using the default termination status if the process
205 // hasn't even started yet.
Lukasz Anforowiczb4b17a42020-04-09 20:57:42206 if (IsStarting())
Bo Liu0d2a2322018-04-19 00:18:09207 termination_info_.status = base::TERMINATION_STATUS_STILL_RUNNING;
Lukasz Anforowicz2e7a0ea2018-04-09 21:21:06208
Bo Liu0d2a2322018-04-19 00:18:09209 // Process doesn't exist, so return the cached termination info.
210 return termination_info_;
kkania@chromium.orgcd69619b2010-05-05 02:41:38211 }
212
Patrick Monette87b033b62022-08-24 20:06:12213#if !BUILDFLAG(IS_ANDROID)
Joe Masonba145282024-03-12 20:18:19214 std::optional<base::TimeDelta> cpu_usage;
Patrick Monette1c4c4172022-09-14 22:04:31215 if (!should_launch_elevated_)
216 cpu_usage = GetCPUUsage(process_.process.Handle());
Patrick Monette87b033b62022-08-24 20:06:12217#endif
218
Bo Liu0d2a2322018-04-19 00:18:09219 termination_info_ = helper_->GetTerminationInfo(process_, known_dead);
jbates@chromium.orgf3c1d3c2011-07-25 18:50:48220
Patrick Monette87b033b62022-08-24 20:06:12221#if !BUILDFLAG(IS_ANDROID)
222 // Get the cumulative CPU usage. This needs to be done before closing the
223 // process handle (on Windows) or reaping the zombie process (on MacOS, Linux,
224 // ChromeOS).
225 termination_info_.cpu_usage = cpu_usage;
226#endif
227
jcivelli828cd7f2017-01-18 19:50:46228 // POSIX: If the process crashed, then the kernel closed the socket for it and
229 // so the child has already died by the time we get here. Since
Bo Liu0d2a2322018-04-19 00:18:09230 // GetTerminationInfo called waitpid with WNOHANG, it'll reap the process.
231 // However, if GetTerminationInfo didn't reap the child (because it was
jcivelli828cd7f2017-01-18 19:50:46232 // still running), we'll need to Terminate via ProcessWatcher. So we can't
233 // close the handle here.
Bo Liu0d2a2322018-04-19 00:18:09234 if (termination_info_.status != base::TERMINATION_STATUS_STILL_RUNNING) {
235 process_.process.Exited(termination_info_.exit_code);
jcivelli828cd7f2017-01-18 19:50:46236 process_.process.Close();
Brian Whiteae2a8b9a2017-11-02 19:10:36237 }
kkania@chromium.orgcd69619b2010-05-05 02:41:38238
Bo Liu0d2a2322018-04-19 00:18:09239 return termination_info_;
ananta@chromium.org358cb8e2011-05-25 02:12:45240}
jam@chromium.org130757672012-10-24 00:26:19241
Wez0abfbf512018-03-03 01:54:45242bool ChildProcessLauncher::Terminate(int exit_code) {
jcivelli828cd7f2017-01-18 19:50:46243 return IsStarting() ? false
244 : ChildProcessLauncherHelper::TerminateProcess(
Wez0abfbf512018-03-03 01:54:45245 GetProcess(), exit_code);
jcivelli828cd7f2017-01-18 19:50:46246}
247
248// static
249bool ChildProcessLauncher::TerminateProcess(const base::Process& process,
Wez0abfbf512018-03-03 01:54:45250 int exit_code) {
251 return ChildProcessLauncherHelper::TerminateProcess(process, exit_code);
jcivelli828cd7f2017-01-18 19:50:46252}
253
Xiaohan Wang1ecfd002022-01-19 22:33:10254#if BUILDFLAG(IS_ANDROID)
Calder Kitagawabf5286652022-09-14 15:38:19255base::android::ChildBindingState
256ChildProcessLauncher::GetEffectiveChildBindingState() {
257 return helper_->GetEffectiveChildBindingState();
258}
259
Min Qinf9dd0302019-03-07 18:54:00260void ChildProcessLauncher::DumpProcessStack() {
261 base::Process to_pass = process_.process.Duplicate();
262 GetProcessLauncherTaskRunner()->PostTask(
263 FROM_HERE, base::BindOnce(&ChildProcessLauncherHelper::DumpProcessStack,
264 helper_, std::move(to_pass)));
265}
266#endif
267
lfg06aac852015-03-23 22:36:10268ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
269 Client* client) {
sievers954e37a2015-03-28 01:50:24270 Client* ret = client_;
271 client_ = client;
272 return ret;
lfg06aac852015-03-23 22:36:10273}
274
Patrick Monetted54f90e2022-12-13 19:03:55275bool RenderProcessPriority::is_background() const {
Patrick Monette350d1e52024-07-22 02:25:23276#if !BUILDFLAG(IS_ANDROID)
Patrick Monette5d200fc2024-07-23 20:19:38277 if (priority_override) {
278 return *priority_override == base::Process::Priority::kBestEffort;
Patrick Monette350d1e52024-07-22 02:25:23279 }
280#endif
Andrew Paseltinereb3045e2021-01-26 16:25:39281 return !visible && !has_media_stream && !boost_for_pending_views &&
Minoru Chikamune56e6a242024-07-17 06:55:35282 !has_foreground_service_worker && !boost_for_loading;
Ben Kellyf4fc4ce02019-02-12 16:10:01283}
284
Patrick Monette7d8aca112024-06-13 12:11:10285base::Process::Priority RenderProcessPriority::GetProcessPriority() const {
Patrick Monette5d200fc2024-07-23 20:19:38286#if !BUILDFLAG(IS_ANDROID)
287 if (priority_override) {
288 return *priority_override;
289 }
290#endif
Patrick Monette7d8aca112024-06-13 12:11:10291 return is_background() ? base::Process::Priority::kBestEffort
292 : base::Process::Priority::kUserBlocking;
293}
294
Patrick Monetted54f90e2022-12-13 19:03:55295bool RenderProcessPriority::operator==(
Patrick Monettebe0144b2024-07-18 21:31:29296 const RenderProcessPriority& other) const = default;
297
298bool RenderProcessPriority::operator!=(
299 const RenderProcessPriority& other) const = default;
Bo Liu168c8642017-08-28 18:26:02300
jam@chromium.org130757672012-10-24 00:26:19301} // namespace content