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.
5 #include "content/browser/utility_process_host_impl.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/utf_string_conversions.h"
12 #include "content/browser/browser_child_process_host_impl.h"
13 #include "content/common/child_process_host_impl.h"
14 #include "content/common/utility_messages.h"
15 #include "content/public/browser/content_browser_client.h"
16 #include "content/public/browser/utility_process_host_client.h"
17 #include "content/public/common/content_switches.h"
18 #include "ipc/ipc_switches.h"
19 #include "ui/base/ui_base_switches.h"
20 #include "webkit/plugins/plugin_switches.h"
24 UtilityProcessHost
* UtilityProcessHost::Create(
25 UtilityProcessHostClient
* client
,
26 base::SequencedTaskRunner
* client_task_runner
) {
27 return new UtilityProcessHostImpl(client
, client_task_runner
);
30 UtilityProcessHostImpl::UtilityProcessHostImpl(
31 UtilityProcessHostClient
* client
,
32 base::SequencedTaskRunner
* client_task_runner
)
34 client_task_runner_(client_task_runner
),
35 is_batch_mode_(false),
38 child_flags_(ChildProcessHost::CHILD_ALLOW_SELF
),
40 child_flags_(ChildProcessHost::CHILD_NORMAL
),
42 use_linux_zygote_(false),
44 process_
.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY
, this));
47 UtilityProcessHostImpl::~UtilityProcessHostImpl() {
48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
49 DCHECK(!is_batch_mode_
);
52 bool UtilityProcessHostImpl::Send(IPC::Message
* message
) {
56 return process_
->Send(message
);
59 bool UtilityProcessHostImpl::StartBatchMode() {
60 CHECK(!is_batch_mode_
);
61 is_batch_mode_
= StartProcess();
62 Send(new UtilityMsg_BatchMode_Started());
63 return is_batch_mode_
;
66 void UtilityProcessHostImpl::EndBatchMode() {
67 CHECK(is_batch_mode_
);
68 is_batch_mode_
= false;
69 Send(new UtilityMsg_BatchMode_Finished());
72 void UtilityProcessHostImpl::SetExposedDir(const FilePath
& dir
) {
76 void UtilityProcessHostImpl::DisableSandbox() {
80 void UtilityProcessHostImpl::EnableZygote() {
81 use_linux_zygote_
= true;
86 void UtilityProcessHostImpl::SetEnv(const base::EnvironmentVector
& env
) {
92 bool UtilityProcessHostImpl::StartProcess() {
99 // Name must be set or metrics_service will crash in any test which
100 // launches a UtilityProcessHost.
101 process_
->SetName(ASCIIToUTF16("utility process"));
103 std::string channel_id
= process_
->GetHost()->CreateChannel();
104 if (channel_id
.empty())
107 const CommandLine
& browser_command_line
= *CommandLine::ForCurrentProcess();
108 int child_flags
= child_flags_
;
110 #if defined(OS_POSIX)
111 bool has_cmd_prefix
= browser_command_line
.HasSwitch(
112 switches::kUtilityCmdPrefix
);
114 // When running under gdb, forking /proc/self/exe ends up forking the gdb
115 // executable instead of Chromium. It is almost safe to assume that no
116 // updates will happen while a developer is running with
117 // |switches::kUtilityCmdPrefix|. See ChildProcessHost::GetChildPath() for
118 // a similar case with Valgrind.
120 child_flags
= ChildProcessHost::CHILD_NORMAL
;
123 FilePath exe_path
= ChildProcessHost::GetChildPath(child_flags
);
124 if (exe_path
.empty()) {
125 NOTREACHED() << "Unable to get utility process binary name.";
129 CommandLine
* cmd_line
= new CommandLine(exe_path
);
130 cmd_line
->AppendSwitchASCII(switches::kProcessType
,
131 switches::kUtilityProcess
);
132 cmd_line
->AppendSwitchASCII(switches::kProcessChannelID
, channel_id
);
133 std::string locale
= GetContentClient()->browser()->GetApplicationLocale();
134 cmd_line
->AppendSwitchASCII(switches::kLang
, locale
);
136 if (browser_command_line
.HasSwitch(switches::kChromeFrame
))
137 cmd_line
->AppendSwitch(switches::kChromeFrame
);
138 if (no_sandbox_
|| browser_command_line
.HasSwitch(switches::kNoSandbox
))
139 cmd_line
->AppendSwitch(switches::kNoSandbox
);
140 #if defined(OS_MACOSX)
141 if (browser_command_line
.HasSwitch(switches::kEnableSandboxLogging
))
142 cmd_line
->AppendSwitch(switches::kEnableSandboxLogging
);
144 if (browser_command_line
.HasSwitch(switches::kDebugPluginLoading
))
145 cmd_line
->AppendSwitch(switches::kDebugPluginLoading
);
147 #if defined(OS_POSIX)
148 // TODO(port): Sandbox this on Linux. Also, zygote this to work with
150 if (has_cmd_prefix
) {
151 // launch the utility child process with some prefix (usually "xterm -e gdb
153 cmd_line
->PrependWrapper(browser_command_line
.GetSwitchValueNative(
154 switches::kUtilityCmdPrefix
));
157 cmd_line
->AppendSwitchPath(switches::kUtilityProcessAllowedDir
, exposed_dir_
);
160 bool use_zygote
= false;
162 #if defined(OS_LINUX)
163 use_zygote
= !no_sandbox_
&& use_linux_zygote_
;
169 #elif defined(OS_POSIX)
178 bool UtilityProcessHostImpl::OnMessageReceived(const IPC::Message
& message
) {
179 client_task_runner_
->PostTask(
181 base::Bind(base::IgnoreResult(
182 &UtilityProcessHostClient::OnMessageReceived
), client_
.get(),
187 void UtilityProcessHostImpl::OnProcessCrashed(int exit_code
) {
188 client_task_runner_
->PostTask(
190 base::Bind(&UtilityProcessHostClient::OnProcessCrashed
, client_
.get(),
194 } // namespace content