Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: content/browser/utility_process_host_impl.cc

Issue 18119009: Make utility process run in-process when running in single-process mode. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: add comment Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/utility_process_host_impl.h" 5 #include "content/browser/utility_process_host_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
10 #include "base/sequenced_task_runner.h" 12 #include "base/sequenced_task_runner.h"
11 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/synchronization/lock.h"
15 #include "base/synchronization/waitable_event.h"
12 #include "content/browser/browser_child_process_host_impl.h" 16 #include "content/browser/browser_child_process_host_impl.h"
17 #include "content/browser/renderer_host/render_process_host_impl.h"
18 #include "content/child/child_process.h"
13 #include "content/common/child_process_host_impl.h" 19 #include "content/common/child_process_host_impl.h"
14 #include "content/common/utility_messages.h" 20 #include "content/common/utility_messages.h"
15 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/content_browser_client.h" 22 #include "content/public/browser/content_browser_client.h"
17 #include "content/public/browser/utility_process_host_client.h" 23 #include "content/public/browser/utility_process_host_client.h"
18 #include "content/public/common/content_switches.h" 24 #include "content/public/common/content_switches.h"
25 #include "content/public/common/process_type.h"
26 #include "content/utility/utility_thread_impl.h"
19 #include "ipc/ipc_switches.h" 27 #include "ipc/ipc_switches.h"
20 #include "ui/base/ui_base_switches.h" 28 #include "ui/base/ui_base_switches.h"
21 #include "webkit/plugins/plugin_switches.h" 29 #include "webkit/plugins/plugin_switches.h"
22 30
23 #if defined(OS_WIN) 31 #if defined(OS_WIN)
24 #include "content/public/common/sandboxed_process_launcher_delegate.h" 32 #include "content/public/common/sandboxed_process_launcher_delegate.h"
25 #endif 33 #endif
26 34
27 namespace content { 35 namespace content {
28 36
29 #if defined(OS_WIN) 37 #if defined(OS_WIN)
30 // NOTE: changes to this class need to be reviewed by the security team. 38 // NOTE: changes to this class need to be reviewed by the security team.
31 class UtilitySandboxedProcessLauncherDelegate 39 class UtilitySandboxedProcessLauncherDelegate
32 : public SandboxedProcessLauncherDelegate { 40 : public SandboxedProcessLauncherDelegate {
33 public: 41 public:
34 explicit UtilitySandboxedProcessLauncherDelegate( 42 explicit UtilitySandboxedProcessLauncherDelegate(
35 const base::FilePath& exposed_dir) : exposed_dir_(exposed_dir) {} 43 const base::FilePath& exposed_dir) : exposed_dir_(exposed_dir) {}
36 virtual ~UtilitySandboxedProcessLauncherDelegate() {} 44 virtual ~UtilitySandboxedProcessLauncherDelegate() {}
37 45
38 virtual void PreSandbox(bool* disable_default_policy, 46 virtual void PreSandbox(bool* disable_default_policy,
39 base::FilePath* exposed_dir) OVERRIDE { 47 base::FilePath* exposed_dir) OVERRIDE {
40 *exposed_dir = exposed_dir_; 48 *exposed_dir = exposed_dir_;
41 } 49 }
42 50
43 private: 51 private:
44 base::FilePath exposed_dir_; 52 base::FilePath exposed_dir_;
45 }; 53 };
46 #endif 54 #endif
47 55
56 class UtilityMainThread : public base::Thread,
57 public base::MessageLoop::DestructionObserver {
58 public:
59 UtilityMainThread(const std::string& channel_id, IPC::Listener* listener)
60 : Thread("Chrome_InProcUtilityThread"),
61 channel_id_(channel_id),
62 listener_(listener),
63 done_event_(false, false),
64 quit_(false) {
65 channel_.reset(new IPC::Channel(
66 channel_id_, IPC::Channel::MODE_SERVER, listener_));
67 CHECK(channel_->Connect());
68 }
69
70 virtual ~UtilityMainThread() {
71 Stop();
72 }
73
74 void WaitForThreadToFlush() {
75 {
76 base::AutoLock auto_lock(quit_lock_);
77 if (quit_)
78 return;
79
80 message_loop()->PostTask(
81 FROM_HERE,
82 base::Bind(&UtilityMainThread::Flush, base::Unretained(this)));
83 }
84 done_event_.Wait();
85 }
86
87 IPC::Channel* channel() const { return channel_.get(); }
88
89 private:
90 // base::Thread implementation:
91 virtual void Init() OVERRIDE {
92 child_process_.reset(new ChildProcess());
93 child_process_->set_main_thread(new UtilityThreadImpl(channel_id_));
94 base::MessageLoop::current()->AddDestructionObserver(this);
95 }
96
97 virtual void CleanUp() OVERRIDE {
98 child_process_.reset();
99
100 // See comment in RendererMainThread.
101 SetThreadWasQuitProperly(true);
102 }
103
104 // base::MessageLoop::DestructionObserver implementation:
105 virtual void WillDestroyCurrentMessageLoop() OVERRIDE {
106 base::AutoLock auto_lock(quit_lock_);
107 quit_ = true;
108 done_event_.Signal();
109 }
110
111 void Flush() {
112 base::RunLoop().RunUntilIdle();
113 done_event_.Signal();
114 }
115
116 std::string channel_id_;
117 scoped_ptr<IPC::Channel> channel_;
118 IPC::Listener* listener_;
119 scoped_ptr<ChildProcess> child_process_;
120 base::WaitableEvent done_event_;
121
122 base::Lock quit_lock_; // Synchronizes access to quit_.
123 bool quit_; // Set to true when the thread destruction observer fires.
124
125 DISALLOW_COPY_AND_ASSIGN(UtilityMainThread);
126 };
127
48 UtilityProcessHost* UtilityProcessHost::Create( 128 UtilityProcessHost* UtilityProcessHost::Create(
49 UtilityProcessHostClient* client, 129 UtilityProcessHostClient* client,
50 base::SequencedTaskRunner* client_task_runner) { 130 base::SequencedTaskRunner* client_task_runner) {
51 return new UtilityProcessHostImpl(client, client_task_runner); 131 return new UtilityProcessHostImpl(client, client_task_runner);
52 } 132 }
53 133
54 UtilityProcessHostImpl::UtilityProcessHostImpl( 134 UtilityProcessHostImpl::UtilityProcessHostImpl(
55 UtilityProcessHostClient* client, 135 UtilityProcessHostClient* client,
56 base::SequencedTaskRunner* client_task_runner) 136 base::SequencedTaskRunner* client_task_runner)
57 : client_(client), 137 : client_(client),
58 client_task_runner_(client_task_runner), 138 client_task_runner_(client_task_runner),
59 is_batch_mode_(false), 139 is_batch_mode_(false),
60 no_sandbox_(false), 140 no_sandbox_(false),
61 #if defined(OS_LINUX) 141 #if defined(OS_LINUX)
62 child_flags_(ChildProcessHost::CHILD_ALLOW_SELF), 142 child_flags_(ChildProcessHost::CHILD_ALLOW_SELF),
63 #else 143 #else
64 child_flags_(ChildProcessHost::CHILD_NORMAL), 144 child_flags_(ChildProcessHost::CHILD_NORMAL),
65 #endif 145 #endif
66 use_linux_zygote_(false), 146 use_linux_zygote_(false),
67 started_(false) { 147 started_(false),
68 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY, this)); 148 fake_process_data_(PROCESS_TYPE_UTILITY) {
69 } 149 }
70 150
71 UtilityProcessHostImpl::~UtilityProcessHostImpl() { 151 UtilityProcessHostImpl::~UtilityProcessHostImpl() {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
73 DCHECK(!is_batch_mode_); 153 DCHECK(!is_batch_mode_);
74 } 154 }
75 155
76 bool UtilityProcessHostImpl::Send(IPC::Message* message) { 156 bool UtilityProcessHostImpl::Send(IPC::Message* message) {
77 if (!StartProcess()) 157 if (!StartProcess())
78 return false; 158 return false;
79 159
160 if (in_process_thread_.get())
161 return in_process_thread_->channel()->Send(message);
162
80 return process_->Send(message); 163 return process_->Send(message);
81 } 164 }
82 165
83 bool UtilityProcessHostImpl::StartBatchMode() { 166 bool UtilityProcessHostImpl::StartBatchMode() {
84 CHECK(!is_batch_mode_); 167 CHECK(!is_batch_mode_);
85 is_batch_mode_ = StartProcess(); 168 is_batch_mode_ = StartProcess();
86 Send(new UtilityMsg_BatchMode_Started()); 169 Send(new UtilityMsg_BatchMode_Started());
87 return is_batch_mode_; 170 return is_batch_mode_;
88 } 171 }
89 172
90 void UtilityProcessHostImpl::EndBatchMode() { 173 void UtilityProcessHostImpl::EndBatchMode() {
91 CHECK(is_batch_mode_); 174 CHECK(is_batch_mode_);
92 is_batch_mode_ = false; 175 is_batch_mode_ = false;
93 Send(new UtilityMsg_BatchMode_Finished()); 176 Send(new UtilityMsg_BatchMode_Finished());
94 } 177 }
95 178
96 void UtilityProcessHostImpl::SetExposedDir(const base::FilePath& dir) { 179 void UtilityProcessHostImpl::SetExposedDir(const base::FilePath& dir) {
97 exposed_dir_ = dir; 180 exposed_dir_ = dir;
98 } 181 }
99 182
100 void UtilityProcessHostImpl::DisableSandbox() { 183 void UtilityProcessHostImpl::DisableSandbox() {
101 no_sandbox_ = true; 184 no_sandbox_ = true;
102 } 185 }
103 186
104 void UtilityProcessHostImpl::EnableZygote() { 187 void UtilityProcessHostImpl::EnableZygote() {
105 use_linux_zygote_ = true; 188 use_linux_zygote_ = true;
106 } 189 }
107 190
108 const ChildProcessData& UtilityProcessHostImpl::GetData() { 191 const ChildProcessData& UtilityProcessHostImpl::GetData() {
192 if (in_process_thread_.get())
193 return fake_process_data_;
194
109 return process_->GetData(); 195 return process_->GetData();
110 } 196 }
111 197
112 #if defined(OS_POSIX) 198 #if defined(OS_POSIX)
113 199
114 void UtilityProcessHostImpl::SetEnv(const base::EnvironmentVector& env) { 200 void UtilityProcessHostImpl::SetEnv(const base::EnvironmentVector& env) {
115 env_ = env; 201 env_ = env;
116 } 202 }
117 203
118 #endif // OS_POSIX 204 #endif // OS_POSIX
119 205
120 bool UtilityProcessHostImpl::StartProcess() { 206 bool UtilityProcessHostImpl::StartProcess() {
121 if (started_) 207 if (started_)
122 return true; 208 return true;
123 started_ = true; 209 started_ = true;
124 210
125 if (is_batch_mode_) 211 if (is_batch_mode_)
126 return true; 212 return true;
127 // Name must be set or metrics_service will crash in any test which
128 // launches a UtilityProcessHost.
129 process_->SetName(ASCIIToUTF16("utility process"));
130 213
131 std::string channel_id = process_->GetHost()->CreateChannel(); 214 if (RenderProcessHost::run_renderer_in_process()) {
132 if (channel_id.empty()) 215 // See comment in RenderProcessHostImpl::Init() for the background on why we
133 return false; 216 // support single process mode this way.
217 const std::string channel_id =
218 IPC::Channel::GenerateVerifiedChannelID(std::string());
219 in_process_thread_.reset(new UtilityMainThread(channel_id, this));
220 in_process_thread_->Start();
221 } else {
222 // Name must be set or metrics_service will crash in any test which
223 // launches a UtilityProcessHost.
224 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY, this));
225 process_->SetName(ASCIIToUTF16("utility process"));
134 226
135 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 227 std::string channel_id = process_->GetHost()->CreateChannel();
136 int child_flags = child_flags_; 228 if (channel_id.empty())
229 return false;
230
231 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
232 int child_flags = child_flags_;
137 233
138 #if defined(OS_POSIX) 234 #if defined(OS_POSIX)
139 bool has_cmd_prefix = browser_command_line.HasSwitch( 235 bool has_cmd_prefix = browser_command_line.HasSwitch(
140 switches::kUtilityCmdPrefix); 236 switches::kUtilityCmdPrefix);
141 237
142 // When running under gdb, forking /proc/self/exe ends up forking the gdb 238 // 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 239 // executable instead of Chromium. It is almost safe to assume that no
144 // updates will happen while a developer is running with 240 // updates will happen while a developer is running with
145 // |switches::kUtilityCmdPrefix|. See ChildProcessHost::GetChildPath() for 241 // |switches::kUtilityCmdPrefix|. See ChildProcessHost::GetChildPath() for
146 // a similar case with Valgrind. 242 // a similar case with Valgrind.
147 if (has_cmd_prefix) 243 if (has_cmd_prefix)
148 child_flags = ChildProcessHost::CHILD_NORMAL; 244 child_flags = ChildProcessHost::CHILD_NORMAL;
149 #endif 245 #endif
150 246
151 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags); 247 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
152 if (exe_path.empty()) { 248 if (exe_path.empty()) {
153 NOTREACHED() << "Unable to get utility process binary name."; 249 NOTREACHED() << "Unable to get utility process binary name.";
154 return false; 250 return false;
155 } 251 }
156 252
157 CommandLine* cmd_line = new CommandLine(exe_path); 253 CommandLine* cmd_line = new CommandLine(exe_path);
158 cmd_line->AppendSwitchASCII(switches::kProcessType, 254 cmd_line->AppendSwitchASCII(switches::kProcessType,
159 switches::kUtilityProcess); 255 switches::kUtilityProcess);
160 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); 256 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
161 std::string locale = GetContentClient()->browser()->GetApplicationLocale(); 257 std::string locale = GetContentClient()->browser()->GetApplicationLocale();
162 cmd_line->AppendSwitchASCII(switches::kLang, locale); 258 cmd_line->AppendSwitchASCII(switches::kLang, locale);
163 259
164 if (no_sandbox_ || browser_command_line.HasSwitch(switches::kNoSandbox)) 260 if (no_sandbox_ || browser_command_line.HasSwitch(switches::kNoSandbox))
165 cmd_line->AppendSwitch(switches::kNoSandbox); 261 cmd_line->AppendSwitch(switches::kNoSandbox);
166 #if defined(OS_MACOSX) 262 #if defined(OS_MACOSX)
167 if (browser_command_line.HasSwitch(switches::kEnableSandboxLogging)) 263 if (browser_command_line.HasSwitch(switches::kEnableSandboxLogging))
168 cmd_line->AppendSwitch(switches::kEnableSandboxLogging); 264 cmd_line->AppendSwitch(switches::kEnableSandboxLogging);
169 #endif 265 #endif
170 if (browser_command_line.HasSwitch(switches::kDebugPluginLoading)) 266 if (browser_command_line.HasSwitch(switches::kDebugPluginLoading))
171 cmd_line->AppendSwitch(switches::kDebugPluginLoading); 267 cmd_line->AppendSwitch(switches::kDebugPluginLoading);
172 268
173 #if defined(OS_POSIX) 269 #if defined(OS_POSIX)
174 // TODO(port): Sandbox this on Linux. Also, zygote this to work with 270 // TODO(port): Sandbox this on Linux. Also, zygote this to work with
175 // Linux updating. 271 // Linux updating.
176 if (has_cmd_prefix) { 272 if (has_cmd_prefix) {
177 // launch the utility child process with some prefix (usually "xterm -e gdb 273 // launch the utility child process with some prefix (usually "xterm -e gd b
178 // --args"). 274 // --args").
179 cmd_line->PrependWrapper(browser_command_line.GetSwitchValueNative( 275 cmd_line->PrependWrapper(browser_command_line.GetSwitchValueNative(
180 switches::kUtilityCmdPrefix)); 276 switches::kUtilityCmdPrefix));
181 } 277 }
182 278
183 cmd_line->AppendSwitchPath(switches::kUtilityProcessAllowedDir, exposed_dir_); 279 cmd_line->AppendSwitchPath(switches::kUtilityProcessAllowedDir, exposed_dir_ );
184 #endif 280 #endif
185 281
186 bool use_zygote = false; 282 bool use_zygote = false;
187 283
188 #if defined(OS_LINUX) 284 #if defined(OS_LINUX)
189 use_zygote = !no_sandbox_ && use_linux_zygote_; 285 use_zygote = !no_sandbox_ && use_linux_zygote_;
190 #endif 286 #endif
191 287
192 process_->Launch( 288 process_->Launch(
193 #if defined(OS_WIN) 289 #if defined(OS_WIN)
194 new UtilitySandboxedProcessLauncherDelegate(exposed_dir_), 290 new UtilitySandboxedProcessLauncherDelegate(exposed_dir_),
195 #elif defined(OS_POSIX) 291 #elif defined(OS_POSIX)
196 use_zygote, 292 use_zygote,
197 env_, 293 env_,
198 #endif 294 #endif
199 cmd_line); 295 cmd_line);
296 }
200 297
201 return true; 298 return true;
202 } 299 }
203 300
204 bool UtilityProcessHostImpl::OnMessageReceived(const IPC::Message& message) { 301 bool UtilityProcessHostImpl::OnMessageReceived(const IPC::Message& message) {
302 if (in_process_thread_.get()) {
303 // When running in single process mode, wait on the thread to flush its
304 // tasks after every message. This is important for unittests so that we
305 // cleanup.
306 in_process_thread_->WaitForThreadToFlush();
307 }
205 client_task_runner_->PostTask( 308 client_task_runner_->PostTask(
206 FROM_HERE, 309 FROM_HERE,
207 base::Bind(base::IgnoreResult( 310 base::Bind(base::IgnoreResult(
208 &UtilityProcessHostClient::OnMessageReceived), client_.get(), 311 &UtilityProcessHostClient::OnMessageReceived), client_.get(),
209 message)); 312 message));
210 return true; 313 return true;
211 } 314 }
212 315
213 void UtilityProcessHostImpl::OnProcessCrashed(int exit_code) { 316 void UtilityProcessHostImpl::OnProcessCrashed(int exit_code) {
214 client_task_runner_->PostTask( 317 client_task_runner_->PostTask(
215 FROM_HERE, 318 FROM_HERE,
216 base::Bind(&UtilityProcessHostClient::OnProcessCrashed, client_.get(), 319 base::Bind(&UtilityProcessHostClient::OnProcessCrashed, client_.get(),
217 exit_code)); 320 exit_code));
218 } 321 }
219 322
220 } // namespace content 323 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698