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