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

Side by Side Diff: chrome/browser/child_process_launcher.cc

Issue 1625015: Refactor ChildProcess and related classes to create a framework outside of br... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 10 years, 8 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
« no previous file with comments | « chrome/browser/child_process_launcher.h ('k') | chrome/browser/gpu_process_host_ui_shim.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 "chrome/browser/child_process_launcher.h"
6
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/scoped_ptr.h"
10 #include "base/thread.h"
11 #include "chrome/browser/chrome_thread.h"
12 #include "chrome/common/chrome_descriptors.h"
13 #include "chrome/common/chrome_switches.h"
14 #include "chrome/common/process_watcher.h"
15 #include "chrome/common/result_codes.h"
16
17 #if defined(OS_WIN)
18 #include "chrome/common/sandbox_policy.h"
19 #elif defined(OS_LINUX)
20 #include "base/singleton.h"
21 #include "chrome/browser/crash_handler_host_linux.h"
22 #include "chrome/browser/zygote_host_linux.h"
23 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
24 #endif
25
26 #if defined(OS_MACOSX)
27 #include "chrome/browser/mach_broker_mac.h"
28 #endif
29
30 #if defined(OS_POSIX)
31 #include "base/global_descriptors_posix.h"
32 #endif
33
34 // TODO(eroman): Debugging helper to make strings show up in mini-dumps.
35 // Remove after done investigating 40447.
36 class StackString {
37 public:
38 explicit StackString(const std::wstring& str) {
39 length_ = str.size();
40 memcpy(&buffer_[0], str.data(),
41 std::min(sizeof(wchar_t) * str.length(),
42 sizeof(buffer_)));
43 }
44
45 std::wstring ToString() {
46 return std::wstring(buffer_, length_);
47 }
48
49 ~StackString() {
50 // Hack to make sure compiler doesn't optimize us away.
51 if (ToString() != ToString())
52 LOG(INFO) << ToString();
53 }
54
55 private:
56 wchar_t buffer_[128];
57 size_t length_;
58 };
59
60 // Having the functionality of ChildProcessLauncher be in an internal
61 // ref counted object allows us to automatically terminate the process when the
62 // parent class destructs, while still holding on to state that we need.
63 class ChildProcessLauncher::Context
64 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
65 public:
66 Context()
67 : starting_(true)
68 #if defined(OS_LINUX)
69 , zygote_(false)
70 #endif
71 {
72 }
73
74 void Launch(
75 #if defined(OS_WIN)
76 const FilePath& exposed_dir,
77 #elif defined(OS_POSIX)
78 bool use_zygote,
79 const base::environment_vector& environ,
80 int ipcfd,
81 #endif
82 CommandLine* cmd_line,
83 Client* client) {
84 client_ = client;
85
86 CHECK(ChromeThread::GetCurrentThreadIdentifier(&client_thread_id_));
87
88 ChromeThread::PostTask(
89 ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
90 NewRunnableMethod(
91 this,
92 &Context::LaunchInternal,
93 #if defined(OS_WIN)
94 exposed_dir,
95 #elif defined(POSIX)
96 use_zygote,
97 environ,
98 ipcfd,
99 #endif
100 cmd_line));
101 }
102
103 void ResetClient() {
104 // No need for locking as this function gets called on the same thread that
105 // client_ would be used.
106 CHECK(ChromeThread::CurrentlyOn(client_thread_id_));
107 client_ = NULL;
108 }
109
110 private:
111 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
112 friend class ChildProcessLauncher;
113
114 ~Context() {
115 Terminate();
116 }
117
118 void LaunchInternal(
119 #if defined(OS_WIN)
120 const FilePath& exposed_dir,
121 #elif defined(OS_POSIX)
122 bool use_zygote,
123 const base::environment_vector& env,
124 int ipcfd,
125 #endif
126 CommandLine* cmd_line) {
127 scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
128 base::ProcessHandle handle = base::kNullProcessHandle;
129 #if defined(OS_WIN)
130 // TODO(eroman): Remove after done investigating 40447.
131 StackString stack_command_line(cmd_line->command_line_string());
132 // This line might crash, since it calls the string copy-constructor:
133 StackString stack_program(cmd_line->program());
134
135 handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir);
136 #elif defined(OS_POSIX)
137
138 #if defined(OS_LINUX)
139 if (use_zygote) {
140 base::GlobalDescriptors::Mapping mapping;
141 mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd));
142 const int crash_signal_fd =
143 Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket();
144 if (crash_signal_fd >= 0) {
145 mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal,
146 crash_signal_fd));
147 }
148 handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping);
149 } else
150 // Fall through to the normal posix case below when we're not zygoting.
151 #endif
152 {
153 base::file_handle_mapping_vector fds_to_map;
154 fds_to_map.push_back(std::make_pair(
155 ipcfd,
156 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
157
158 #if defined(OS_LINUX)
159 // On Linux, we need to add some extra file descriptors for crash handling
160 // and the sandbox.
161 bool is_renderer =
162 cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
163 switches::kRendererProcess;
164 bool is_plugin =
165 cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
166 switches::kPluginProcess;
167
168 if (is_renderer || is_plugin) {
169 int crash_signal_fd;
170 if (is_renderer) {
171 crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()->
172 GetDeathSignalSocket();
173 } else {
174 crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()->
175 GetDeathSignalSocket();
176 }
177 if (crash_signal_fd >= 0) {
178 fds_to_map.push_back(std::make_pair(
179 crash_signal_fd,
180 kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor));
181 }
182 }
183 if (is_renderer) {
184 const int sandbox_fd =
185 Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
186 fds_to_map.push_back(std::make_pair(
187 sandbox_fd,
188 kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
189 }
190 #endif // defined(OS_LINUX)
191
192 // Actually launch the app.
193 bool launched;
194 #if defined(OS_MACOSX)
195 task_t child_task;
196 launched = base::LaunchAppAndGetTask(
197 cmd_line->argv(), env, fds_to_map, false, &child_task, &handle);
198 if (launched && child_task != MACH_PORT_NULL) {
199 MachBroker::instance()->RegisterPid(
200 handle,
201 MachBroker::MachInfo().SetTask(child_task));
202 }
203 #else
204 launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map,
205 /* wait= */false, &handle);
206 #endif
207 if (!launched)
208 handle = base::kNullProcessHandle;
209 }
210 #endif // else defined(OS_POSIX)
211
212 ChromeThread::PostTask(
213 client_thread_id_, FROM_HERE,
214 NewRunnableMethod(
215 this,
216 &ChildProcessLauncher::Context::Notify,
217 #if defined(OS_LINUX)
218 use_zygote,
219 #endif
220 handle));
221 }
222
223 void Notify(
224 #if defined(OS_LINUX)
225 bool zygote,
226 #endif
227 base::ProcessHandle handle) {
228 starting_ = false;
229 process_.set_handle(handle);
230 #if defined(OS_LINUX)
231 zygote_ = zygote;
232 #endif
233 if (client_) {
234 client_->OnProcessLaunched();
235 } else {
236 Terminate();
237 }
238 }
239
240 void Terminate() {
241 if (!process_.handle())
242 return;
243
244 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
245 // don't this on the UI/IO threads.
246 ChromeThread::PostTask(
247 ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
248 NewRunnableFunction(
249 &ChildProcessLauncher::Context::TerminateInternal,
250 #if defined(OS_LINUX)
251 zygote_,
252 #endif
253 process_.handle()));
254 process_.set_handle(base::kNullProcessHandle);
255 }
256
257 static void TerminateInternal(
258 #if defined(OS_LINUX)
259 bool zygote,
260 #endif
261 base::ProcessHandle handle) {
262 base::Process process(handle);
263 // Client has gone away, so just kill the process. Using exit code 0
264 // means that UMA won't treat this as a crash.
265 process.Terminate(ResultCodes::NORMAL_EXIT);
266 // On POSIX, we must additionally reap the child.
267 #if defined(OS_POSIX)
268 #if defined(OS_LINUX)
269 if (zygote) {
270 // If the renderer was created via a zygote, we have to proxy the reaping
271 // through the zygote process.
272 Singleton<ZygoteHost>()->EnsureProcessTerminated(handle);
273 } else
274 #endif // OS_LINUX
275 {
276 ProcessWatcher::EnsureProcessTerminated(handle);
277 }
278 #endif // OS_POSIX
279 process.Close();
280 }
281
282 Client* client_;
283 ChromeThread::ID client_thread_id_;
284 base::Process process_;
285 bool starting_;
286
287 #if defined(OS_LINUX)
288 bool zygote_;
289 #endif
290 };
291
292
293 ChildProcessLauncher::ChildProcessLauncher(
294 #if defined(OS_WIN)
295 const FilePath& exposed_dir,
296 #elif defined(OS_POSIX)
297 bool use_zygote,
298 const base::environment_vector& environ,
299 int ipcfd,
300 #endif
301 CommandLine* cmd_line,
302 Client* client) {
303 context_ = new Context();
304 context_->Launch(
305 #if defined(OS_WIN)
306 exposed_dir,
307 #elif defined(OS_POSIX)
308 use_zygote,
309 environ,
310 ipcfd,
311 #endif
312 cmd_line,
313 client);
314 }
315
316 ChildProcessLauncher::~ChildProcessLauncher() {
317 context_->ResetClient();
318 }
319
320 bool ChildProcessLauncher::IsStarting() {
321 return context_->starting_;
322 }
323
324 base::ProcessHandle ChildProcessLauncher::GetHandle() {
325 DCHECK(!context_->starting_);
326 return context_->process_.handle();
327 }
328
329 bool ChildProcessLauncher::DidProcessCrash() {
330 bool did_crash, child_exited;
331 base::ProcessHandle handle = context_->process_.handle();
332 #if defined(OS_LINUX)
333 if (context_->zygote_) {
334 did_crash = Singleton<ZygoteHost>()->DidProcessCrash(handle, &child_exited);
335 } else
336 #endif
337 {
338 did_crash = base::DidProcessCrash(&child_exited, handle);
339 }
340
341 // POSIX: If the process crashed, then the kernel closed the socket for it
342 // and so the child has already died by the time we get here. Since
343 // DidProcessCrash called waitpid with WNOHANG, it'll reap the process.
344 // However, if DidProcessCrash didn't reap the child, we'll need to in
345 // Terminate via ProcessWatcher. So we can't close the handle here.
346 if (child_exited)
347 context_->process_.Close();
348
349 return did_crash;
350 }
351
352 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
353 DCHECK(!context_->starting_);
354 context_->process_.SetProcessBackgrounded(background);
355 }
OLDNEW
« no previous file with comments | « chrome/browser/child_process_launcher.h ('k') | chrome/browser/gpu_process_host_ui_shim.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698