1 // Copyright (c) 2012 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/utility_process_host.h"
6
7 #include <utility>
8
9 #include "base/base_switches.h"
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/command_line.h"
13 #include "base/files/file_path.h"
14 #include "base/i18n/base_i18n_switches.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/stl_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "build/chromeos_buildflags.h"
19 #include "components/network_session_configurator/common/network_switches.h"
20 #include "content/browser/browser_child_process_host_impl.h"
21 #include "content/browser/renderer_host/render_process_host_impl.h"
22 #include "content/browser/utility_sandbox_delegate.h"
23 #include "content/browser/v8_snapshot_files.h"
24 #include "content/common/child_process_host_impl.h"
25 #include "content/common/in_process_child_thread_params.h"
26 #include "content/public/browser/browser_task_traits.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/content_browser_client.h"
29 #include "content/public/common/content_client.h"
30 #include "content/public/common/content_features.h"
31 #include "content/public/common/content_switches.h"
32 #include "content/public/common/process_type.h"
33 #include "content/public/common/sandboxed_process_launcher_delegate.h"
34 #include "media/base/media_switches.h"
35 #include "media/webrtc/webrtc_switches.h"
36 #include "sandbox/policy/sandbox_type.h"
37 #include "sandbox/policy/switches.h"
38 #include "services/network/public/cpp/network_switches.h"
39 #include "services/service_manager/public/cpp/interface_provider.h"
40 #include "ui/base/ui_base_switches.h"
41 #include "ui/gl/gl_switches.h"
42
43 #if defined(OS_MAC)
44 #include "components/os_crypt/os_crypt_switches.h"
45 #endif
46
47 namespace content {
48
49 UtilityMainThreadFactoryFunction g_utility_main_thread_factory = nullptr;
50
RegisterUtilityMainThreadFactory(UtilityMainThreadFactoryFunction create)51 void UtilityProcessHost::RegisterUtilityMainThreadFactory(
52 UtilityMainThreadFactoryFunction create) {
53 g_utility_main_thread_factory = create;
54 }
55
UtilityProcessHost()56 UtilityProcessHost::UtilityProcessHost()
57 : UtilityProcessHost(nullptr /* client */) {}
58
UtilityProcessHost(std::unique_ptr<Client> client)59 UtilityProcessHost::UtilityProcessHost(std::unique_ptr<Client> client)
60 : sandbox_type_(sandbox::policy::SandboxType::kUtility),
61 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
62 child_flags_(ChildProcessHost::CHILD_ALLOW_SELF),
63 #else
64 child_flags_(ChildProcessHost::CHILD_NORMAL),
65 #endif
66 started_(false),
67 name_(base::ASCIIToUTF16("utility process")),
68 client_(std::move(client)) {
69 process_.reset(new BrowserChildProcessHostImpl(
70 PROCESS_TYPE_UTILITY, this, ChildProcessHost::IpcMode::kNormal));
71 }
72
~UtilityProcessHost()73 UtilityProcessHost::~UtilityProcessHost() {
74 DCHECK_CURRENTLY_ON(BrowserThread::IO);
75 if (client_ && launch_state_ == LaunchState::kLaunchComplete)
76 client_->OnProcessTerminatedNormally();
77 }
78
AsWeakPtr()79 base::WeakPtr<UtilityProcessHost> UtilityProcessHost::AsWeakPtr() {
80 return weak_ptr_factory_.GetWeakPtr();
81 }
82
Send(IPC::Message * message)83 bool UtilityProcessHost::Send(IPC::Message* message) {
84 if (!StartProcess())
85 return false;
86
87 return process_->Send(message);
88 }
89
SetSandboxType(sandbox::policy::SandboxType sandbox_type)90 void UtilityProcessHost::SetSandboxType(
91 sandbox::policy::SandboxType sandbox_type) {
92 sandbox_type_ = sandbox_type;
93 }
94
GetData()95 const ChildProcessData& UtilityProcessHost::GetData() {
96 return process_->GetData();
97 }
98
99 #if defined(OS_POSIX)
SetEnv(const base::EnvironmentMap & env)100 void UtilityProcessHost::SetEnv(const base::EnvironmentMap& env) {
101 env_ = env;
102 }
103 #endif
104
Start()105 bool UtilityProcessHost::Start() {
106 return StartProcess();
107 }
108
RunService(const std::string & service_name,mojo::PendingReceiver<service_manager::mojom::Service> receiver,service_manager::Service::CreatePackagedServiceInstanceCallback callback)109 void UtilityProcessHost::RunService(
110 const std::string& service_name,
111 mojo::PendingReceiver<service_manager::mojom::Service> receiver,
112 service_manager::Service::CreatePackagedServiceInstanceCallback callback) {
113 if (launch_state_ == LaunchState::kLaunchFailed) {
114 std::move(callback).Run(base::nullopt);
115 return;
116 }
117
118 process_->GetHost()->RunService(service_name, std::move(receiver));
119 if (launch_state_ == LaunchState::kLaunchComplete) {
120 std::move(callback).Run(process_->GetProcess().Pid());
121 } else {
122 DCHECK_EQ(launch_state_, LaunchState::kLaunchInProgress);
123 pending_run_service_callbacks_.push_back(std::move(callback));
124 }
125 }
126
SetMetricsName(const std::string & metrics_name)127 void UtilityProcessHost::SetMetricsName(const std::string& metrics_name) {
128 metrics_name_ = metrics_name;
129 }
130
SetName(const base::string16 & name)131 void UtilityProcessHost::SetName(const base::string16& name) {
132 name_ = name;
133 }
134
SetServiceIdentity(const service_manager::Identity & identity)135 void UtilityProcessHost::SetServiceIdentity(
136 const service_manager::Identity& identity) {
137 service_identity_ = identity;
138 }
139
SetExtraCommandLineSwitches(std::vector<std::string> switches)140 void UtilityProcessHost::SetExtraCommandLineSwitches(
141 std::vector<std::string> switches) {
142 extra_switches_ = std::move(switches);
143 }
144
GetChildProcess()145 mojom::ChildProcess* UtilityProcessHost::GetChildProcess() {
146 return static_cast<ChildProcessHostImpl*>(process_->GetHost())
147 ->child_process();
148 }
149
StartProcess()150 bool UtilityProcessHost::StartProcess() {
151 if (started_)
152 return true;
153
154 started_ = true;
155 process_->SetName(name_);
156 process_->SetMetricsName(metrics_name_);
157 process_->GetHost()->CreateChannelMojo();
158
159 if (RenderProcessHost::run_renderer_in_process()) {
160 DCHECK(g_utility_main_thread_factory);
161 // See comment in RenderProcessHostImpl::Init() for the background on why we
162 // support single process mode this way.
163 in_process_thread_.reset(g_utility_main_thread_factory(
164 InProcessChildThreadParams(GetIOThreadTaskRunner({}),
165 process_->GetInProcessMojoInvitation())));
166 in_process_thread_->Start();
167 } else {
168 const base::CommandLine& browser_command_line =
169 *base::CommandLine::ForCurrentProcess();
170
171 bool has_cmd_prefix =
172 browser_command_line.HasSwitch(switches::kUtilityCmdPrefix);
173
174 #if defined(OS_ANDROID)
175 // readlink("/prof/self/exe") sometimes fails on Android at startup.
176 // As a workaround skip calling it here, since the executable name is
177 // not needed on Android anyway. See crbug.com/500854.
178 std::unique_ptr<base::CommandLine> cmd_line =
179 std::make_unique<base::CommandLine>(base::CommandLine::NO_PROGRAM);
180 if (sandbox_type_ == sandbox::policy::SandboxType::kNetwork &&
181 base::FeatureList::IsEnabled(features::kWarmUpNetworkProcess)) {
182 process_->EnableWarmUpConnection();
183 }
184 #else
185 int child_flags = child_flags_;
186
187 // When running under gdb, forking /proc/self/exe ends up forking the gdb
188 // executable instead of Chromium. It is almost safe to assume that no
189 // updates will happen while a developer is running with
190 // |switches::kUtilityCmdPrefix|. See ChildProcessHost::GetChildPath() for
191 // a similar case with Valgrind.
192 if (has_cmd_prefix)
193 child_flags = ChildProcessHost::CHILD_NORMAL;
194
195 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
196 if (exe_path.empty()) {
197 NOTREACHED() << "Unable to get utility process binary name.";
198 return false;
199 }
200
201 std::unique_ptr<base::CommandLine> cmd_line =
202 std::make_unique<base::CommandLine>(exe_path);
203 #endif
204
205 cmd_line->AppendSwitchASCII(switches::kProcessType,
206 switches::kUtilityProcess);
207 // Specify the type of utility process for debugging/profiling purposes.
208 cmd_line->AppendSwitchASCII(switches::kUtilitySubType, metrics_name_);
209 BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line.get());
210 BrowserChildProcessHostImpl::CopyTraceStartupFlags(cmd_line.get());
211 std::string locale = GetContentClient()->browser()->GetApplicationLocale();
212 cmd_line->AppendSwitchASCII(switches::kLang, locale);
213
214 #if defined(OS_WIN)
215 cmd_line->AppendArg(switches::kPrefetchArgumentOther);
216 #endif // defined(OS_WIN)
217
218 sandbox::policy::SetCommandLineFlagsForSandboxType(cmd_line.get(),
219 sandbox_type_);
220
221 // Browser command-line switches to propagate to the utility process.
222 static const char* const kSwitchNames[] = {
223 network::switches::kAdditionalTrustTokenKeyCommitments,
224 network::switches::kForceEffectiveConnectionType,
225 network::switches::kHostResolverRules,
226 network::switches::kIgnoreCertificateErrorsSPKIList,
227 network::switches::kIgnoreUrlFetcherCertRequests,
228 network::switches::kLogNetLog,
229 network::switches::kNetLogCaptureMode,
230 network::switches::kExplicitlyAllowedPorts,
231 sandbox::policy::switches::kNoSandbox,
232 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !BUILDFLAG(IS_LACROS)
233 switches::kDisableDevShmUsage,
234 #endif
235 #if defined(OS_MAC)
236 sandbox::policy::switches::kEnableSandboxLogging,
237 os_crypt::switches::kUseMockKeychain,
238 #endif
239 switches::kDisableTestCerts,
240 switches::kEnableExperimentalCookieFeatures,
241 switches::kEnableLogging,
242 switches::kForceTextDirection,
243 switches::kForceUIDirection,
244 switches::kIgnoreCertificateErrors,
245 switches::kLoggingLevel,
246 switches::kOverrideUseSoftwareGLForTests,
247 switches::kOverrideEnabledCdmInterfaceVersion,
248 switches::kProxyServer,
249 switches::kDisableAcceleratedMjpegDecode,
250 switches::kUseFakeDeviceForMediaStream,
251 switches::kUseFakeMjpegDecodeAccelerator,
252 switches::kUseFileForFakeVideoCapture,
253 switches::kUseMockCertVerifierForTesting,
254 switches::kMockCertVerifierDefaultResultForTesting,
255 switches::kUtilityStartupDialog,
256 switches::kUseGL,
257 switches::kV,
258 switches::kVModule,
259 #if defined(OS_ANDROID)
260 switches::kEnableReachedCodeProfiler,
261 switches::kReachedCodeSamplingIntervalUs,
262 #endif
263 switches::kEnableExperimentalWebPlatformFeatures,
264 // These flags are used by the audio service:
265 switches::kAudioBufferSize,
266 switches::kAudioServiceQuitTimeoutMs,
267 switches::kDisableAudioOutput,
268 switches::kFailAudioStreamCreation,
269 switches::kMuteAudio,
270 switches::kUseFileForFakeAudioCapture,
271 switches::kAgcStartupMinVolume,
272 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FREEBSD) || \
273 defined(OS_SOLARIS) || defined(OS_DRAGONFLY)
274 switches::kAlsaInputDevice,
275 switches::kAlsaOutputDevice,
276 #endif
277 #if defined(USE_CRAS)
278 switches::kUseCras,
279 #endif
280 #if defined(OS_WIN)
281 switches::kDisableHighResTimer,
282 switches::kEnableExclusiveAudio,
283 switches::kForceWaveAudio,
284 switches::kRaiseTimerFrequency,
285 switches::kTrySupportedChannelLayouts,
286 switches::kWaveOutBuffers,
287 switches::kWebXrForceRuntime,
288 sandbox::policy::switches::kAddXrAppContainerCaps,
289 #endif
290 network::switches::kUseFirstPartySet,
291 };
292 cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
293 base::size(kSwitchNames));
294
295 network_session_configurator::CopyNetworkSwitches(browser_command_line,
296 cmd_line.get());
297
298 if (has_cmd_prefix) {
299 // Launch the utility child process with some prefix
300 // (usually "xterm -e gdb --args").
301 cmd_line->PrependWrapper(browser_command_line.GetSwitchValueNative(
302 switches::kUtilityCmdPrefix));
303 }
304
305 for (const auto& extra_switch : extra_switches_)
306 cmd_line->AppendSwitch(extra_switch);
307
308 std::unique_ptr<UtilitySandboxedProcessLauncherDelegate> delegate =
309 std::make_unique<UtilitySandboxedProcessLauncherDelegate>(
310 sandbox_type_, env_, *cmd_line);
311
312 #if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
313 if (child_flags == ChildProcessHost::CHILD_LAUNCH_X86_64) {
314 delegate->set_launch_x86_64(true);
315 }
316 #endif // OS_MAC && ARCH_CPU_ARM64
317
318 process_->LaunchWithPreloadedFiles(std::move(delegate), std::move(cmd_line),
319 GetV8SnapshotFilesToPreload(), true);
320 }
321
322 return true;
323 }
324
OnMessageReceived(const IPC::Message & message)325 bool UtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
326 return true;
327 }
328
OnProcessLaunched()329 void UtilityProcessHost::OnProcessLaunched() {
330 launch_state_ = LaunchState::kLaunchComplete;
331 for (auto& callback : pending_run_service_callbacks_)
332 std::move(callback).Run(process_->GetProcess().Pid());
333 pending_run_service_callbacks_.clear();
334 if (client_)
335 client_->OnProcessLaunched(process_->GetProcess());
336 }
337
OnProcessLaunchFailed(int error_code)338 void UtilityProcessHost::OnProcessLaunchFailed(int error_code) {
339 launch_state_ = LaunchState::kLaunchFailed;
340 for (auto& callback : pending_run_service_callbacks_)
341 std::move(callback).Run(base::nullopt);
342 pending_run_service_callbacks_.clear();
343 }
344
OnProcessCrashed(int exit_code)345 void UtilityProcessHost::OnProcessCrashed(int exit_code) {
346 if (!client_)
347 return;
348
349 // Take ownership of |client_| so the destructor doesn't notify it of
350 // termination.
351 auto client = std::move(client_);
352 #if defined(OS_ANDROID)
353 // OnProcessCrashed() is always called on Android even in the case of normal
354 // process termination. |clean_exit| gives us a reliable indication of whether
355 // this was really a crash or just normal termination.
356 if (process_->GetTerminationInfo(true /* known_dead */).clean_exit) {
357 client->OnProcessTerminatedNormally();
358 return;
359 }
360 #endif
361 client->OnProcessCrashed();
362 }
363
GetServiceName()364 base::Optional<std::string> UtilityProcessHost::GetServiceName() {
365 if (!service_identity_)
366 return metrics_name_;
367 return service_identity_->name();
368 }
369
370 } // namespace content
371