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/strings/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/browser_thread.h"
16 #include "content/public/browser/content_browser_client.h"
17 #include "content/public/browser/utility_process_host_client.h"
18 #include "content/public/common/content_switches.h"
19 #include "ipc/ipc_switches.h"
20 #include "ui/base/ui_base_switches.h"
21 #include "webkit/plugins/plugin_switches.h"
24 #include "content/public/common/sandboxed_process_launcher_delegate.h"
30 // NOTE: changes to this class need to be reviewed by the security team.
31 class UtilitySandboxedProcessLauncherDelegate
32 : public SandboxedProcessLauncherDelegate
{
34 explicit UtilitySandboxedProcessLauncherDelegate(
35 const base::FilePath
& exposed_dir
) : exposed_dir_(exposed_dir
) {}
36 virtual ~UtilitySandboxedProcessLauncherDelegate() {}
38 virtual void PreSandbox(bool* disable_default_policy
,
39 base::FilePath
* exposed_dir
) OVERRIDE
{
40 *exposed_dir
= exposed_dir_
;
44 base::FilePath exposed_dir_
;
48 UtilityProcessHost
* UtilityProcessHost::Create(
49 UtilityProcessHostClient
* client
,
50 base::SequencedTaskRunner
* client_task_runner
) {
51 return new UtilityProcessHostImpl(client
, client_task_runner
);
54 UtilityProcessHostImpl::UtilityProcessHostImpl(
55 UtilityProcessHostClient
* client
,
56 base::SequencedTaskRunner
* client_task_runner
)
58 client_task_runner_(client_task_runner
),
59 is_batch_mode_(false),
62 child_flags_(ChildProcessHost::CHILD_ALLOW_SELF
),
64 child_flags_(ChildProcessHost::CHILD_NORMAL
),
66 use_linux_zygote_(false),
68 process_
.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY
, this));
71 UtilityProcessHostImpl::~UtilityProcessHostImpl() {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
73 DCHECK(!is_batch_mode_
);
76 bool UtilityProcessHostImpl::Send(IPC::Message
* message
) {
80 return process_
->Send(message
);
83 bool UtilityProcessHostImpl::StartBatchMode() {
84 CHECK(!is_batch_mode_
);
85 is_batch_mode_
= StartProcess();
86 Send(new UtilityMsg_BatchMode_Started());
87 return is_batch_mode_
;
90 void UtilityProcessHostImpl::EndBatchMode() {
91 CHECK(is_batch_mode_
);
92 is_batch_mode_
= false;
93 Send(new UtilityMsg_BatchMode_Finished());
96 void UtilityProcessHostImpl::SetExposedDir(const base::FilePath
& dir
) {
100 void UtilityProcessHostImpl::DisableSandbox() {
104 void UtilityProcessHostImpl::EnableZygote() {
105 use_linux_zygote_
= true;
108 const ChildProcessData
& UtilityProcessHostImpl::GetData() {
109 return process_
->GetData();
112 #if defined(OS_POSIX)
114 void UtilityProcessHostImpl::SetEnv(const base::EnvironmentVector
& env
) {
120 bool UtilityProcessHostImpl::StartProcess() {
127 // Name must be set or metrics_service will crash in any test which
128 // launches a UtilityProcessHost.
129 process_
->SetName(ASCIIToUTF16("utility process"));
131 std::string channel_id
= process_
->GetHost()->CreateChannel();
132 if (channel_id
.empty())
135 const CommandLine
& browser_command_line
= *CommandLine::ForCurrentProcess();
136 int child_flags
= child_flags_
;
138 #if defined(OS_POSIX)
139 bool has_cmd_prefix
= browser_command_line
.HasSwitch(
140 switches::kUtilityCmdPrefix
);
142 // When running under gdb, forking /proc/self/exe ends up forking the gdb
143 // executable instead of Chromium. It is almost safe to assume that no
144 // updates will happen while a developer is running with
145 // |switches::kUtilityCmdPrefix|. See ChildProcessHost::GetChildPath() for
146 // a similar case with Valgrind.
148 child_flags
= ChildProcessHost::CHILD_NORMAL
;
151 base::FilePath exe_path
= ChildProcessHost::GetChildPath(child_flags
);
152 if (exe_path
.empty()) {
153 NOTREACHED() << "Unable to get utility process binary name.";
157 CommandLine
* cmd_line
= new CommandLine(exe_path
);
158 cmd_line
->AppendSwitchASCII(switches::kProcessType
,
159 switches::kUtilityProcess
);
160 cmd_line
->AppendSwitchASCII(switches::kProcessChannelID
, channel_id
);
161 std::string locale
= GetContentClient()->browser()->GetApplicationLocale();
162 cmd_line
->AppendSwitchASCII(switches::kLang
, locale
);
164 if (no_sandbox_
|| browser_command_line
.HasSwitch(switches::kNoSandbox
))
165 cmd_line
->AppendSwitch(switches::kNoSandbox
);
166 #if defined(OS_MACOSX)
167 if (browser_command_line
.HasSwitch(switches::kEnableSandboxLogging
))
168 cmd_line
->AppendSwitch(switches::kEnableSandboxLogging
);
170 if (browser_command_line
.HasSwitch(switches::kDebugPluginLoading
))
171 cmd_line
->AppendSwitch(switches::kDebugPluginLoading
);
173 #if defined(OS_POSIX)
174 // TODO(port): Sandbox this on Linux. Also, zygote this to work with
176 if (has_cmd_prefix
) {
177 // launch the utility child process with some prefix (usually "xterm -e gdb
179 cmd_line
->PrependWrapper(browser_command_line
.GetSwitchValueNative(
180 switches::kUtilityCmdPrefix
));
183 cmd_line
->AppendSwitchPath(switches::kUtilityProcessAllowedDir
, exposed_dir_
);
186 bool use_zygote
= false;
188 #if defined(OS_LINUX)
189 use_zygote
= !no_sandbox_
&& use_linux_zygote_
;
194 new UtilitySandboxedProcessLauncherDelegate(exposed_dir_
),
195 #elif defined(OS_POSIX)
204 bool UtilityProcessHostImpl::OnMessageReceived(const IPC::Message
& message
) {
205 client_task_runner_
->PostTask(
207 base::Bind(base::IgnoreResult(
208 &UtilityProcessHostClient::OnMessageReceived
), client_
.get(),
213 void UtilityProcessHostImpl::OnProcessCrashed(int exit_code
) {
214 client_task_runner_
->PostTask(
216 base::Bind(&UtilityProcessHostClient::OnProcessCrashed
, client_
.get(),
220 } // namespace content