blob: 1d2ae87bf16802c7fbc0a49ba9b02f79e8b1c593 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2012 The Chromium Authors
[email protected]d27893f62010-07-03 05:47:422// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Will Harriscd57b832023-01-05 20:03:105#include "content/browser/child_process_host_impl.h"
[email protected]d27893f62010-07-03 05:47:426
[email protected]4306c3792011-12-02 01:57:537#include <limits>
Avi Drissman5d5d48d62022-01-07 20:23:588#include <tuple>
[email protected]4306c3792011-12-02 01:57:539
[email protected]3cb7cc9532014-01-08 22:55:5110#include "base/atomic_sequence_num.h"
Sebastien Marchandbd02bc29e2020-03-11 15:53:3611#include "base/clang_profiling_buildflags.h"
[email protected]d27893f62010-07-03 05:47:4212#include "base/command_line.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3513#include "base/files/file.h"
[email protected]57999812013-02-24 05:40:5214#include "base/files/file_path.h"
Daniel Chengc0581992019-03-29 04:52:5615#include "base/hash/hash.h"
[email protected]8c40f322011-08-24 03:33:3616#include "base/logging.h"
Gabriel Charette9f60dd12020-03-06 20:48:0417#include "base/memory/ptr_util.h"
asvitkine8d51e9d2016-09-02 23:55:4318#include "base/metrics/histogram_macros.h"
reveman22dd9292014-10-13 20:52:0519#include "base/numerics/safe_math.h"
[email protected]d27893f62010-07-03 05:47:4220#include "base/path_service.h"
[email protected]71ed8e022013-07-25 14:39:5721#include "base/process/process_metrics.h"
[email protected]4306c3792011-12-02 01:57:5322#include "base/rand_util.h"
erikchen5708aae2015-09-14 17:45:1223#include "base/synchronization/lock.h"
Sean Maher5b9af51f2022-11-21 15:32:4724#include "base/task/single_thread_task_runner.h"
avia9aa7a82015-12-25 03:06:3125#include "build/build_config.h"
Dominic Farolino1f773782020-09-08 20:03:3626#include "content/common/content_constants_internal.h"
Lukasz Anforowicz2b8b86232021-08-18 23:35:5027#include "content/common/pseudonymization_salt.h"
Emily Andrews2eab36a2024-12-03 20:15:4828#include "content/public/browser/browser_thread.h"
Will Harriscd57b832023-01-05 20:03:1029#include "content/public/browser/child_process_host_delegate.h"
30#include "content/public/browser/content_browser_client.h"
Richard Knolldb46ceb2021-01-14 20:39:3731#include "content/public/common/content_client.h"
[email protected]5d921d4c2011-10-21 22:26:1432#include "content/public/common/content_paths.h"
[email protected]c08950d22011-10-13 22:20:2933#include "content/public/common/content_switches.h"
rockotda9887902016-08-19 20:46:4234#include "ipc/ipc.mojom.h"
[email protected]5c41e6e12012-03-17 02:20:4635#include "ipc/ipc_channel.h"
amistryd4aa70d2016-06-23 07:52:3736#include "ipc/ipc_channel_mojo.h"
Ken Rockot95c888a42018-02-11 05:54:1137#include "services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom.h"
rockot734fb662016-10-15 16:41:3038#include "services/service_manager/public/cpp/interface_provider.h"
[email protected]d27893f62010-07-03 05:47:4239
Xiaohan Wangb3178932022-01-11 00:08:2740#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
[email protected]d27893f62010-07-03 05:47:4241#include "base/linux_util.h"
Xiaohan Wangb3178932022-01-11 00:08:2742#elif BUILDFLAG(IS_MAC)
Avi Drissmaneac566b02023-08-18 02:56:2143#include "base/apple/foundation_util.h"
Will Harriscd57b832023-01-05 20:03:1044#include "content/browser/mac_helpers.h"
Xiaohan Wangb3178932022-01-11 00:08:2745#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
[email protected]d27893f62010-07-03 05:47:4246
[email protected]4734d0b2011-12-03 07:10:4447namespace content {
[email protected]d27893f62010-07-03 05:47:4248
Lei Zhang0e004cb2021-12-01 16:43:3449ChildProcessHost::~ChildProcessHost() = default;
50
[email protected]4734d0b2011-12-03 07:10:4451// static
Ayu Ishii75cc1062019-01-08 01:27:3752std::unique_ptr<ChildProcessHost> ChildProcessHost::Create(
Tom Sepez7bf89002025-07-17 23:44:0453 ChildProcessHostDelegate* delegate) {
54 return base::WrapUnique(new ChildProcessHostImpl(delegate));
[email protected]d27893f62010-07-03 05:47:4255}
56
57// static
[email protected]a7329162013-02-07 19:21:4858base::FilePath ChildProcessHost::GetChildPath(int flags) {
59 base::FilePath child_path;
[email protected]d27893f62010-07-03 05:47:4260
[email protected]479278702014-08-11 20:32:0961 child_path = base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
[email protected]d27893f62010-07-03 05:47:4262 switches::kBrowserSubprocessPath);
[email protected]d27893f62010-07-03 05:47:4263
Xiaohan Wangb3178932022-01-11 00:08:2764#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
[email protected]d27893f62010-07-03 05:47:4265 // Use /proc/self/exe rather than our known binary path so updates
66 // can't swap out the binary from underneath us.
Will Harriscd57b832023-01-05 20:03:1067 if (child_path.empty() && flags & CHILD_ALLOW_SELF) {
[email protected]a7329162013-02-07 19:21:4868 child_path = base::FilePath(base::kProcSelfExe);
Will Harriscd57b832023-01-05 20:03:1069 }
[email protected]d27893f62010-07-03 05:47:4270#endif
71
72 // On most platforms, the child executable is the same as the current
73 // executable.
Will Harriscd57b832023-01-05 20:03:1074 if (child_path.empty()) {
Avi Drissman1cb5e9f2018-05-01 15:53:2875 base::PathService::Get(CHILD_PROCESS_EXE, &child_path);
Will Harriscd57b832023-01-05 20:03:1076 }
Robert Sesek4be26982019-06-17 17:41:2877
Xiaohan Wangb3178932022-01-11 00:08:2778#if BUILDFLAG(IS_MAC)
Robert Sesek4be26982019-06-17 17:41:2879 std::string child_base_name = child_path.BaseName().value();
80
Avi Drissmaneac566b02023-08-18 02:56:2181 if (flags != CHILD_NORMAL && base::apple::AmIBundled()) {
Robert Sesek4be26982019-06-17 17:41:2882 // This is a specialized helper, with the |child_path| at
83 // ../Framework.framework/Versions/X/Helpers/Chromium Helper.app/Contents/
84 // MacOS/Chromium Helper. Go back up to the "Helpers" directory to select
85 // a different variant.
86 child_path = child_path.DirName().DirName().DirName().DirName();
87
88 if (flags == CHILD_RENDERER) {
89 child_base_name += kMacHelperSuffix_renderer;
Robert Sesek413f6032019-07-19 21:46:5090 } else if (flags == CHILD_GPU) {
91 child_base_name += kMacHelperSuffix_gpu;
Robert Sesek4be26982019-06-17 17:41:2892 } else if (flags == CHILD_PLUGIN) {
93 child_base_name += kMacHelperSuffix_plugin;
Richard Knolldb46ceb2021-01-14 20:39:3794 } else if (flags > CHILD_EMBEDDER_FIRST) {
Marshall Greenblatt46a40552023-04-21 20:23:3695 child_base_name +=
96 GetContentClient()->browser()->GetChildProcessSuffix(flags);
Robert Sesek4be26982019-06-17 17:41:2897 } else {
Peter Boströmfc7ddc182024-10-31 19:37:2198 NOTREACHED();
Robert Sesek4be26982019-06-17 17:41:2899 }
100
101 child_path = child_path.Append(child_base_name + ".app")
102 .Append("Contents")
103 .Append("MacOS")
104 .Append(child_base_name);
105 }
Xiaohan Wang6028ac22022-01-15 19:18:41106#endif // BUILDFLAG(IS_MAC)
Robert Sesek4be26982019-06-17 17:41:28107
[email protected]d27893f62010-07-03 05:47:42108 return child_path;
109}
110
Tom Sepez7bf89002025-07-17 23:44:04111ChildProcessHostImpl::ChildProcessHostImpl(ChildProcessHostDelegate* delegate)
112 : delegate_(delegate), opening_channel_(false) {
113 child_process_.Bind(mojo::PendingRemote<mojom::ChildProcess>(
114 mojo_invitation_->AttachMessagePipe(kChildProcessReceiverAttachmentName),
115 /*version=*/0));
116 receiver_.Bind(mojo::PendingReceiver<mojom::ChildProcessHost>(
117 mojo_invitation_->AttachMessagePipe(
118 kChildProcessHostRemoteAttachmentName)));
119 receiver_.set_disconnect_handler(
120 base::BindOnce(&ChildProcessHostImpl::OnDisconnectedFromChildProcess,
121 base::Unretained(this)));
Ken Rockot692493f2019-11-18 22:36:57122}
[email protected]4734d0b2011-12-03 07:10:44123
Tom Sepez893f420f2025-07-01 23:02:30124ChildProcessHostImpl::~ChildProcessHostImpl() = default;
[email protected]4734d0b2011-12-03 07:10:44125
Ken Rockotced31272019-08-02 21:12:18126void ChildProcessHostImpl::BindReceiver(mojo::GenericPendingReceiver receiver) {
127 child_process_->BindReceiver(std::move(receiver));
128}
129
Georg Neis35ff854b2024-12-17 02:02:08130#if BUILDFLAG(IS_CHROMEOS)
Andrea Orru966ff882022-09-08 03:24:24131void ChildProcessHostImpl::ReinitializeLogging(
132 uint32_t logging_dest,
133 base::ScopedFD log_file_descriptor) {
134 auto logging_settings = mojom::LoggingSettings::New();
135 logging_settings->logging_dest = logging_dest;
136 logging_settings->log_file_descriptor =
137 mojo::PlatformHandle(std::move(log_file_descriptor));
138 child_process()->ReinitializeLogging(std::move(logging_settings));
139}
Georg Neis35ff854b2024-12-17 02:02:08140#endif // BUILDFLAG(IS_CHROMEOS)
Andrea Orru966ff882022-09-08 03:24:24141
Ken Rockot9836cfb72021-06-16 23:16:02142base::Process& ChildProcessHostImpl::GetPeerProcess() {
143 if (!peer_process_.IsValid()) {
144 const base::Process& process = delegate_->GetProcess();
145 if (process.IsValid()) {
146 peer_process_ = base::Process::OpenWithExtraPrivileges(process.Pid());
Will Harriscd57b832023-01-05 20:03:10147 if (!peer_process_.IsValid()) {
Ken Rockot9836cfb72021-06-16 23:16:02148 peer_process_ = process.Duplicate();
Will Harriscd57b832023-01-05 20:03:10149 }
Ken Rockot9836cfb72021-06-16 23:16:02150 DCHECK(peer_process_.IsValid());
151 }
152 }
153
154 return peer_process_;
155}
156
[email protected]4734d0b2011-12-03 07:10:44157void ChildProcessHostImpl::ForceShutdown() {
Ken Rockot62fb4352019-07-18 16:03:38158 child_process_->ProcessShutdown();
[email protected]bdae9812011-10-15 00:33:03159}
[email protected]91443fc2010-07-14 05:08:46160
Arthur Sonzognic686e8f2024-01-11 08:36:37161std::optional<mojo::OutgoingInvitation>&
Ken Rockot692493f2019-11-18 22:36:57162ChildProcessHostImpl::GetMojoInvitation() {
163 return mojo_invitation_;
164}
165
rockotda9887902016-08-19 20:46:42166void ChildProcessHostImpl::CreateChannelMojo() {
Tom Sepez7bf89002025-07-17 23:44:04167 DCHECK(!channel_);
168 DCHECK(child_process_);
Ken Rockot10bca422019-12-04 05:47:59169
Tom Sepez7bf89002025-07-17 23:44:04170 mojo::ScopedMessagePipeHandle bootstrap =
171 mojo_invitation_->AttachMessagePipe(kLegacyIpcBootstrapAttachmentName);
172 channel_ = IPC::ChannelMojo::Create(
173 std::move(bootstrap), IPC::Channel::MODE_SERVER, this,
174 base::SingleThreadTaskRunner::GetCurrentDefault(),
175 base::SingleThreadTaskRunner::GetCurrentDefault());
176
rockotda9887902016-08-19 20:46:42177 DCHECK(channel_);
178
Ken Rockot9836cfb72021-06-16 23:16:02179 // Since we're initializing a legacy IPC Channel, we will use its connection
Tom Sepez7bf89002025-07-17 23:44:04180 // status to monitor child process lifetime instead of using the status of
181 // the `receiver_` endpoint.
Will Harriscd57b832023-01-05 20:03:10182 if (receiver_.is_bound()) {
Ken Rockot9836cfb72021-06-16 23:16:02183 receiver_.set_disconnect_handler(base::NullCallback());
Will Harriscd57b832023-01-05 20:03:10184 }
Ken Rockot9836cfb72021-06-16 23:16:02185
rockotda9887902016-08-19 20:46:42186 bool initialized = InitChannel();
187 DCHECK(initialized);
188}
189
amistryab52b0c2016-06-07 04:22:57190bool ChildProcessHostImpl::InitChannel() {
Will Harriscd57b832023-01-05 20:03:10191 if (!channel_->Connect()) {
amistryab52b0c2016-06-07 04:22:57192 return false;
Will Harriscd57b832023-01-05 20:03:10193 }
[email protected]d27893f62010-07-03 05:47:42194
sadrul6c5aed8c2017-01-11 23:11:44195 delegate_->OnChannelInitialized(channel_.get());
[email protected]d27893f62010-07-03 05:47:42196 opening_channel_ = true;
197
amistryab52b0c2016-06-07 04:22:57198 return true;
[email protected]d27893f62010-07-03 05:47:42199}
200
Ken Rockot9836cfb72021-06-16 23:16:02201void ChildProcessHostImpl::OnDisconnectedFromChildProcess() {
202 if (channel_) {
203 opening_channel_ = false;
204 delegate_->OnChannelError();
Ken Rockot9836cfb72021-06-16 23:16:02205 }
206
207 // This will delete host_, which will also destroy this!
208 delegate_->OnChildDisconnected();
209}
210
[email protected]4734d0b2011-12-03 07:10:44211bool ChildProcessHostImpl::IsChannelOpening() {
212 return opening_channel_;
213}
214
Marijn Kruisselbrink67f41012024-04-17 00:35:53215// static
Emily Andrews2eab36a2024-12-03 20:15:48216ChildProcessId ChildProcessHost::GenerateChildProcessUniqueId() {
217 CHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]3cb7cc9532014-01-08 22:55:51218 // Historically, this function returned ids started with 1, so in several
219 // places in the code a value of 0 (rather than kInvalidUniqueID) was used as
220 // an invalid value. So we retain those semantics.
Emily Andrews2eab36a2024-12-03 20:15:48221 static ChildProcessId::Generator child_process_id_generator;
222 return child_process_id_generator.GenerateNextId();
[email protected]4306c3792011-12-02 01:57:53223}
224
Emily Andrews2eab36a2024-12-03 20:15:48225uint64_t ChildProcessHostImpl::ChildProcessIdToTracingProcessId(
226 ChildProcessId child_process_id) {
ssid1050d802015-07-28 20:28:14227 // In single process mode, all the children are hosted in the same process,
228 // therefore the generated memory dump guids should not be conditioned by the
229 // child process id. The clients need not be aware of SPM and the conversion
230 // takes care of the SPM special case while translating child process ids to
231 // tracing process ids.
232 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
Will Harriscd57b832023-01-05 20:03:10233 switches::kSingleProcess)) {
chiniforooshan6e4c5072017-03-17 07:56:56234 return memory_instrumentation::mojom::kServiceTracingProcessId;
Will Harriscd57b832023-01-05 20:03:10235 }
ssid1050d802015-07-28 20:28:14236
237 // The hash value is incremented so that the tracing id is never equal to
238 // MemoryDumpManager::kInvalidTracingProcessId.
Tom Sepez5972fdf2024-08-05 23:20:00239 return static_cast<uint64_t>(
240 base::PersistentHash(base::byte_span_from_ref(child_process_id))) +
ssid1050d802015-07-28 20:28:14241 1;
242}
243
Emily Andrews2eab36a2024-12-03 20:15:48244uint64_t ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
245 int child_process_id) {
246 return ChildProcessIdToTracingProcessId(ChildProcessId(child_process_id));
247}
248
Ken Rockot9836cfb72021-06-16 23:16:02249void ChildProcessHostImpl::Ping(PingCallback callback) {
250 std::move(callback).Run();
251}
252
Ken Rockot4f8c3c32019-08-16 16:32:33253void ChildProcessHostImpl::BindHostReceiver(
254 mojo::GenericPendingReceiver receiver) {
255 delegate_->BindHostReceiver(std::move(receiver));
256}
257
avia9aa7a82015-12-25 03:06:31258void ChildProcessHostImpl::OnChannelConnected(int32_t peer_pid) {
Lukasz Anforowicz2b8b86232021-08-18 23:35:50259 // Propagate the pseudonymization salt to all the child processes.
260 //
Lukasz Anforowiczde7891f2023-11-08 22:42:55261 // Doing this as the first step in this method helps to minimize scenarios
262 // where child process runs code that depends on the pseudonymization salt
263 // before it has been set. See also https://crbug.com/1479308#c5
264 //
Lukasz Anforowicz2b8b86232021-08-18 23:35:50265 // TODO(dullweber, lukasza): Figure out if it is possible to reset the salt
266 // at a regular interval (on the order of hours?). The browser would need
267 // to be responsible for 1) deciding when the refresh happens and 2) pushing
268 // the updated salt to all the child processes.
269 child_process_->SetPseudonymizationSalt(GetPseudonymizationSalt());
270
Ken Rockot9836cfb72021-06-16 23:16:02271 // We ignore the `peer_pid` argument, which ultimately comes over IPC from the
272 // remote process, in favor of the PID already known by the browser after
273 // launching the process. This is partly because IPC Channel is being phased
274 // out and some process types no longer use it, but also because there's
275 // really no need to get this information from the child process when we
276 // already have it.
277 //
Alison Gale53c77f62024-04-22 15:16:27278 // TODO(crbug.com/41256971): Remove the peer_pid argument altogether from
Ken Rockot9836cfb72021-06-16 23:16:02279 // IPC::Listener::OnChannelConnected.
280 const base::Process& peer_process = GetPeerProcess();
281 base::ProcessId pid =
282 peer_process.IsValid() ? peer_process.Pid() : base::GetCurrentProcId();
[email protected]4cb43102011-12-02 20:24:49283 opening_channel_ = false;
Ken Rockot9836cfb72021-06-16 23:16:02284 delegate_->OnChannelConnected(pid);
[email protected]d27893f62010-07-03 05:47:42285}
286
[email protected]4734d0b2011-12-03 07:10:44287void ChildProcessHostImpl::OnChannelError() {
Ken Rockot9836cfb72021-06-16 23:16:02288 OnDisconnectedFromChildProcess();
[email protected]d27893f62010-07-03 05:47:42289}
290
[email protected]ef2f6ba2014-05-15 23:06:07291void ChildProcessHostImpl::OnBadMessageReceived(const IPC::Message& message) {
292 delegate_->OnBadMessageReceived(message);
293}
294
Sebastien Marchandf552e982020-09-09 20:19:38295#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
296void ChildProcessHostImpl::DumpProfilingData(base::OnceClosure callback) {
297 child_process_->WriteClangProfilingProfile(std::move(callback));
298}
Will Harris6f5f50a2021-12-03 17:39:45299
300void ChildProcessHostImpl::SetProfilingFile(base::File file) {
301 child_process_->SetProfilingFile(std::move(file));
302}
Sebastien Marchandf552e982020-09-09 20:19:38303#endif
304
Takashi Sakamoto9fe220a82022-12-12 16:41:13305#if BUILDFLAG(IS_ANDROID)
306// Notifies the child process of memory pressure level.
307void ChildProcessHostImpl::NotifyMemoryPressureToChildProcess(
308 base::MemoryPressureListener::MemoryPressureLevel level) {
309 child_process()->OnMemoryPressure(level);
310}
311#endif
312
Etienne Pierre-doraye5313362024-07-18 20:07:24313void ChildProcessHostImpl::SetBatterySaverMode(
314 bool battery_saver_mode_enabled) {
315 child_process()->SetBatterySaverMode(battery_saver_mode_enabled);
316}
317
[email protected]4734d0b2011-12-03 07:10:44318} // namespace content