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

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

Issue 1022703007: Simplify ChildProcessLauncher (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@launcher
Patch Set: default arg, rebase Created 5 years, 9 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
« no previous file with comments | « content/browser/child_process_launcher.h ('k') | content/browser/gpu/gpu_process_host.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/child_process_launcher.h" 5 #include "content/browser/child_process_launcher.h"
6 6
7 #include <utility> // For std::pair.
8
9 #include "base/bind.h" 7 #include "base/bind.h"
10 #include "base/command_line.h" 8 #include "base/command_line.h"
11 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
12 #include "base/files/scoped_file.h"
13 #include "base/logging.h" 10 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
15 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
16 #include "base/process/process.h" 13 #include "base/process/process.h"
17 #include "base/profiler/scoped_tracker.h" 14 #include "base/profiler/scoped_tracker.h"
18 #include "base/synchronization/lock.h" 15 #include "base/synchronization/lock.h"
19 #include "base/threading/thread.h" 16 #include "base/threading/thread.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/content_browser_client.h" 17 #include "content/public/browser/content_browser_client.h"
22 #include "content/public/common/content_descriptors.h" 18 #include "content/public/common/content_descriptors.h"
23 #include "content/public/common/content_switches.h" 19 #include "content/public/common/content_switches.h"
24 #include "content/public/common/result_codes.h" 20 #include "content/public/common/result_codes.h"
25 #include "content/public/common/sandboxed_process_launcher_delegate.h" 21 #include "content/public/common/sandboxed_process_launcher_delegate.h"
26 22
27 #if defined(OS_WIN) 23 #if defined(OS_WIN)
28 #include "base/files/file_path.h" 24 #include "base/files/file_path.h"
29 #include "content/common/sandbox_win.h" 25 #include "content/common/sandbox_win.h"
30 #include "content/public/common/sandbox_init.h" 26 #include "content/public/common/sandbox_init.h"
(...skipping 12 matching lines...) Expand all
43 #include "content/common/child_process_sandbox_support_impl_linux.h" 39 #include "content/common/child_process_sandbox_support_impl_linux.h"
44 #endif 40 #endif
45 41
46 #if defined(OS_POSIX) 42 #if defined(OS_POSIX)
47 #include "base/posix/global_descriptors.h" 43 #include "base/posix/global_descriptors.h"
48 #include "content/browser/file_descriptor_info_impl.h" 44 #include "content/browser/file_descriptor_info_impl.h"
49 #endif 45 #endif
50 46
51 namespace content { 47 namespace content {
52 48
53 // Having the functionality of ChildProcessLauncher be in an internal 49 namespace {
54 // ref counted object allows us to automatically terminate the process when the
55 // parent class destructs, while still holding on to state that we need.
56 class ChildProcessLauncher::Context
57 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
58 public:
59 Context();
60 50
61 // Posts a task to a dedicated thread to do the actual work. 51 typedef base::Callback<void(bool,
62 // Must be called on the UI thread. 52 #if defined(OS_ANDROID)
63 void Launch(SandboxedProcessLauncherDelegate* delegate, 53 base::ScopedFD,
64 base::CommandLine* cmd_line, 54 #endif
65 int child_process_id, 55 base::Process)> NotifyCallback;
66 Client* client);
67 56
68 #if defined(OS_ANDROID) 57 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
69 // Called on the UI thread with the operation result. Calls Notify(). 58 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
70 static void OnChildProcessStarted(
71 // |this_object| is NOT thread safe. Only use it to post a task back.
72 scoped_refptr<Context> this_object,
73 BrowserThread::ID client_thread_id,
74 const base::TimeTicks begin_launch_time,
75 base::ProcessHandle handle);
76 #endif
77
78 // Resets the client (the client is going away).
79 void ResetClient();
80
81 bool starting() const { return starting_; }
82
83 const base::Process& process() const { return process_; }
84
85 int exit_code() const { return exit_code_; }
86
87 base::TerminationStatus termination_status() const {
88 return termination_status_;
89 }
90
91 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
92 terminate_child_on_shutdown_ = terminate_on_shutdown;
93 }
94
95 void UpdateTerminationStatus(bool known_dead);
96
97 void Close() { process_.Close(); }
98
99 void SetProcessBackgrounded(bool background);
100
101 Client* ReplaceClientForTest(Client* client) {
102 Client* ret = client_;
103 client_ = client;
104 return ret;
105 }
106
107 private:
108 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
109
110 ~Context() {
111 Terminate();
112 }
113
114 static void RecordHistograms(base::TimeTicks begin_launch_time);
115 static void RecordLaunchHistograms(base::TimeDelta launch_time);
116
117 // Performs the actual work of launching the process.
118 // Runs on the PROCESS_LAUNCHER thread.
119 static void LaunchInternal(
120 // |this_object| is NOT thread safe. Only use it to post a task back.
121 scoped_refptr<Context> this_object,
122 BrowserThread::ID client_thread_id,
123 int child_process_id,
124 SandboxedProcessLauncherDelegate* delegate,
125 base::CommandLine* cmd_line);
126
127 // Notifies the client about the result of the operation.
128 // Runs on the UI thread.
129 void Notify(
130 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
131 bool zygote,
132 #endif
133 base::Process process);
134
135 void Terminate();
136
137 static void SetProcessBackgroundedInternal(base::Process process,
138 bool background);
139
140 static void TerminateInternal(
141 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
142 bool zygote,
143 #endif
144 base::Process process);
145
146 Client* client_;
147 BrowserThread::ID client_thread_id_;
148 base::Process process_;
149 base::TerminationStatus termination_status_;
150 int exit_code_;
151 #if defined(OS_ANDROID)
152 // The fd to close after creating the process.
153 base::ScopedFD ipcfd_;
154 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
155 bool zygote_;
156 #endif
157 bool starting_;
158 // Controls whether the child process should be terminated on browser
159 // shutdown. Default behavior is to terminate the child.
160 bool terminate_child_on_shutdown_;
161 };
162
163 ChildProcessLauncher::Context::Context()
164 : client_(NULL),
165 client_thread_id_(BrowserThread::UI),
166 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
167 exit_code_(RESULT_CODE_NORMAL_EXIT),
168 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
169 zygote_(false),
170 #endif
171 starting_(true),
172 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
173 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
174 defined(UNDEFINED_SANITIZER)
175 terminate_child_on_shutdown_(false) {
176 #else
177 terminate_child_on_shutdown_(true) {
178 #endif
179 }
180
181 void ChildProcessLauncher::Context::Launch(
182 SandboxedProcessLauncherDelegate* delegate,
183 base::CommandLine* cmd_line,
184 int child_process_id,
185 Client* client) {
186 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
187 client_ = client;
188
189 #if defined(OS_ANDROID)
190 // Android only supports renderer, sandboxed utility and gpu.
191 std::string process_type =
192 cmd_line->GetSwitchValueASCII(switches::kProcessType);
193 CHECK(process_type == switches::kGpuProcess ||
194 process_type == switches::kRendererProcess ||
195 process_type == switches::kUtilityProcess)
196 << "Unsupported process type: " << process_type;
197
198 // Non-sandboxed utility or renderer process are currently not supported.
199 DCHECK(process_type == switches::kGpuProcess ||
200 !cmd_line->HasSwitch(switches::kNoSandbox));
201
202 // We need to close the client end of the IPC channel to reliably detect
203 // child termination. We will close this fd after we create the child
204 // process which is asynchronous on Android.
205 ipcfd_.reset(delegate->TakeIpcFd().release());
206 #endif
207 BrowserThread::PostTask(
208 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
209 base::Bind(&Context::LaunchInternal,
210 make_scoped_refptr(this),
211 client_thread_id_,
212 child_process_id,
213 delegate,
214 cmd_line));
215 }
216
217 #if defined(OS_ANDROID)
218 // static
219 void ChildProcessLauncher::Context::OnChildProcessStarted(
220 // |this_object| is NOT thread safe. Only use it to post a task back.
221 scoped_refptr<Context> this_object,
222 BrowserThread::ID client_thread_id,
223 const base::TimeTicks begin_launch_time,
224 base::ProcessHandle handle) {
225 RecordHistograms(begin_launch_time);
226 if (BrowserThread::CurrentlyOn(client_thread_id)) {
227 // This is always invoked on the UI thread which is commonly the
228 // |client_thread_id| so we can shortcut one PostTask.
229 this_object->Notify(base::Process(handle));
230 } else {
231 BrowserThread::PostTask(
232 client_thread_id, FROM_HERE,
233 base::Bind(&ChildProcessLauncher::Context::Notify,
234 this_object,
235 base::Passed(base::Process(handle))));
236 }
237 }
238 #endif
239
240 void ChildProcessLauncher::Context::ResetClient() {
241 // No need for locking as this function gets called on the same thread that
242 // client_ would be used.
243 CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
244 client_ = NULL;
245 }
246
247 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead) {
248 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
249 if (zygote_) {
250 termination_status_ = ZygoteHostImpl::GetInstance()->
251 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
252 } else if (known_dead) {
253 termination_status_ =
254 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
255 } else {
256 #elif defined(OS_MACOSX)
257 if (known_dead) {
258 termination_status_ =
259 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
260 } else {
261 #elif defined(OS_ANDROID)
262 if (IsChildProcessOomProtected(process_.Handle())) {
263 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
264 } else {
265 #else
266 {
267 #endif
268 termination_status_ =
269 base::GetTerminationStatus(process_.Handle(), &exit_code_);
270 }
271 }
272
273 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background) {
274 base::Process to_pass = process_.Duplicate();
275 BrowserThread::PostTask(
276 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
277 base::Bind(&Context::SetProcessBackgroundedInternal,
278 base::Passed(&to_pass), background));
279 }
280
281 // static
282 void ChildProcessLauncher::Context::RecordHistograms(
283 base::TimeTicks begin_launch_time) {
284 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
285 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
286 RecordLaunchHistograms(launch_time);
287 } else {
288 BrowserThread::PostTask(
289 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
290 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
291 launch_time));
292 }
293 }
294
295 // static
296 void ChildProcessLauncher::Context::RecordLaunchHistograms(
297 base::TimeDelta launch_time) {
298 // Log the launch time, separating out the first one (which will likely be 59 // Log the launch time, separating out the first one (which will likely be
299 // slower due to the rest of the browser initializing at the same time). 60 // slower due to the rest of the browser initializing at the same time).
300 static bool done_first_launch = false; 61 static bool done_first_launch = false;
301 if (done_first_launch) { 62 if (done_first_launch) {
302 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); 63 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
303 } else { 64 } else {
304 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); 65 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
305 done_first_launch = true; 66 done_first_launch = true;
306 } 67 }
307 } 68 }
308 69
309 // static 70 #if defined(OS_ANDROID)
310 void ChildProcessLauncher::Context::LaunchInternal( 71 // TODO(sievers): Remove this by defining better what happens on what
311 // |this_object| is NOT thread safe. Only use it to post a task back. 72 // thread in the corresponding Java code.
312 scoped_refptr<Context> this_object, 73 void OnChildProcessStartedAndroid(const NotifyCallback& callback,
313 BrowserThread::ID client_thread_id, 74 BrowserThread::ID client_thread_id,
314 int child_process_id, 75 const base::TimeTicks begin_launch_time,
315 SandboxedProcessLauncherDelegate* delegate, 76 base::ScopedFD ipcfd,
316 base::CommandLine* cmd_line) { 77 base::ProcessHandle handle) {
78 // This can be called on the launcher thread or UI thread.
79 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
80 BrowserThread::PostTask(
81 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
82 base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
83
84 base::Closure callback_on_client_thread(
85 base::Bind(callback, false, base::Passed(&ipcfd),
86 base::Passed(base::Process(handle))));
87 if (BrowserThread::CurrentlyOn(client_thread_id)) {
88 callback_on_client_thread.Run();
89 } else {
90 BrowserThread::PostTask(
91 client_thread_id, FROM_HERE, callback_on_client_thread);
92 }
93 }
94 #endif
95
96 void LaunchOnLauncherThread(const NotifyCallback& callback,
97 BrowserThread::ID client_thread_id,
98 int child_process_id,
99 SandboxedProcessLauncherDelegate* delegate,
100 #if defined(OS_ANDROID)
101 base::ScopedFD ipcfd,
102 #endif
103 base::CommandLine* cmd_line) {
104 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
317 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); 105 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
318 #if defined(OS_WIN) 106 #if defined(OS_WIN)
107 bool use_zygote = false;
319 bool launch_elevated = delegate->ShouldLaunchElevated(); 108 bool launch_elevated = delegate->ShouldLaunchElevated();
320 #elif defined(OS_ANDROID)
321 // Uses |ipcfd_| instead of |ipcfd| on Android.
322 #elif defined(OS_MACOSX) 109 #elif defined(OS_MACOSX)
110 bool use_zygote = false;
323 base::EnvironmentMap env = delegate->GetEnvironment(); 111 base::EnvironmentMap env = delegate->GetEnvironment();
324 base::ScopedFD ipcfd = delegate->TakeIpcFd(); 112 base::ScopedFD ipcfd = delegate->TakeIpcFd();
325 #elif defined(OS_POSIX) 113 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
326 bool use_zygote = delegate->ShouldUseZygote(); 114 bool use_zygote = delegate->ShouldUseZygote();
327 base::EnvironmentMap env = delegate->GetEnvironment(); 115 base::EnvironmentMap env = delegate->GetEnvironment();
328 base::ScopedFD ipcfd = delegate->TakeIpcFd(); 116 base::ScopedFD ipcfd = delegate->TakeIpcFd();
329 #endif 117 #endif
330 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line); 118 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
331 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); 119 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
332 120
333 base::Process process; 121 base::Process process;
334 #if defined(OS_WIN) 122 #if defined(OS_WIN)
335 if (launch_elevated) { 123 if (launch_elevated) {
336 base::LaunchOptions options; 124 base::LaunchOptions options;
337 options.start_hidden = true; 125 options.start_hidden = true;
338 process = base::LaunchElevatedProcess(*cmd_line, options); 126 process = base::LaunchElevatedProcess(*cmd_line, options);
339 } else { 127 } else {
340 process = StartSandboxedProcess(delegate, cmd_line); 128 process = StartSandboxedProcess(delegate, cmd_line);
341 } 129 }
342 #elif defined(OS_POSIX) 130 #elif defined(OS_POSIX)
343 std::string process_type = 131 std::string process_type =
344 cmd_line->GetSwitchValueASCII(switches::kProcessType); 132 cmd_line->GetSwitchValueASCII(switches::kProcessType);
345 scoped_ptr<FileDescriptorInfo> files_to_register( 133 scoped_ptr<FileDescriptorInfo> files_to_register(
346 FileDescriptorInfoImpl::Create()); 134 FileDescriptorInfoImpl::Create());
347 135
348 #if defined(OS_ANDROID) 136 #if defined(OS_ANDROID)
349 files_to_register->Share(kPrimaryIPCChannel, this_object->ipcfd_.get()); 137 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
350 #else 138 #else
351 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass()); 139 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
352 #endif 140 #endif
353 #endif 141 #endif
354 142
355 #if defined(OS_ANDROID) 143 #if defined(OS_ANDROID)
356 // Android WebView runs in single process, ensure that we never get here 144 // Android WebView runs in single process, ensure that we never get here
357 // when running in single process mode. 145 // when running in single process mode.
358 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); 146 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
359 147
360 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( 148 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
361 *cmd_line, child_process_id, files_to_register.get()); 149 *cmd_line, child_process_id, files_to_register.get());
362 150
363 StartChildProcess( 151 StartChildProcess(
364 cmd_line->argv(), 152 cmd_line->argv(), child_process_id, files_to_register.Pass(),
365 child_process_id, 153 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
366 files_to_register.Pass(), 154 begin_launch_time, base::Passed(&ipcfd)));
367 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
368 this_object,
369 client_thread_id,
370 begin_launch_time));
371 155
372 #elif defined(OS_POSIX) 156 #elif defined(OS_POSIX)
373 // We need to close the client end of the IPC channel to reliably detect 157 // We need to close the client end of the IPC channel to reliably detect
374 // child termination. 158 // child termination.
375 159
376 #if !defined(OS_MACOSX) 160 #if !defined(OS_MACOSX)
377 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( 161 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
378 *cmd_line, child_process_id, files_to_register.get()); 162 *cmd_line, child_process_id, files_to_register.get());
379 if (use_zygote) { 163 if (use_zygote) {
380 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest( 164 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 if (process.IsValid()) 224 if (process.IsValid())
441 broker->AddPlaceholderForPid(process.Pid(), child_process_id); 225 broker->AddPlaceholderForPid(process.Pid(), child_process_id);
442 226
443 // After updating the broker, release the lock and let the child's 227 // After updating the broker, release the lock and let the child's
444 // messasge be processed on the broker's thread. 228 // messasge be processed on the broker's thread.
445 broker->GetLock().Release(); 229 broker->GetLock().Release();
446 #endif // defined(OS_MACOSX) 230 #endif // defined(OS_MACOSX)
447 } 231 }
448 #endif // else defined(OS_POSIX) 232 #endif // else defined(OS_POSIX)
449 #if !defined(OS_ANDROID) 233 #if !defined(OS_ANDROID)
450 if (process.IsValid()) 234 if (process.IsValid()) {
451 RecordHistograms(begin_launch_time); 235 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
452 BrowserThread::PostTask( 236 begin_launch_time);
453 client_thread_id, FROM_HERE, 237 }
454 base::Bind(&Context::Notify, 238 BrowserThread::PostTask(client_thread_id, FROM_HERE,
455 this_object.get(), 239 base::Bind(callback,
456 #if defined(OS_POSIX) && !defined(OS_MACOSX) 240 use_zygote,
457 use_zygote, 241 base::Passed(&process)));
458 #endif
459 base::Passed(&process)));
460 #endif // !defined(OS_ANDROID) 242 #endif // !defined(OS_ANDROID)
461 } 243 }
462 244
463 void ChildProcessLauncher::Context::Notify( 245 void TerminateOnLauncherThread(bool zygote, base::Process process) {
464 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 246 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
465 bool zygote,
466 #endif
467 base::Process process) {
468 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
469 // is fixed.
470 tracked_objects::ScopedTracker tracking_profile1(
471 FROM_HERE_WITH_EXPLICIT_FUNCTION(
472 "465841 ChildProcessLauncher::Context::Notify::Start"));
473
474 #if defined(OS_ANDROID)
475 // Finally close the ipcfd
476 base::ScopedFD ipcfd_closer = ipcfd_.Pass();
477 #endif
478 starting_ = false;
479 process_ = process.Pass();
480 if (!process_.IsValid())
481 LOG(ERROR) << "Failed to launch child process";
482
483 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
484 zygote_ = zygote;
485 #endif
486 if (client_) {
487 if (process_.IsValid()) {
488 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
489 // is fixed.
490 tracked_objects::ScopedTracker tracking_profile2(
491 FROM_HERE_WITH_EXPLICIT_FUNCTION(
492 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
493 client_->OnProcessLaunched();
494 } else {
495 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
496 // is fixed.
497 tracked_objects::ScopedTracker tracking_profile3(
498 FROM_HERE_WITH_EXPLICIT_FUNCTION(
499 "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
500 client_->OnProcessLaunchFailed();
501 }
502 } else {
503 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
504 // is fixed.
505 tracked_objects::ScopedTracker tracking_profile4(
506 FROM_HERE_WITH_EXPLICIT_FUNCTION(
507 "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
508 Terminate();
509 }
510 }
511
512 void ChildProcessLauncher::Context::Terminate() {
513 if (!process_.IsValid())
514 return;
515
516 if (!terminate_child_on_shutdown_)
517 return;
518
519 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
520 // don't this on the UI/IO threads.
521 BrowserThread::PostTask(
522 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
523 base::Bind(&Context::TerminateInternal,
524 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
525 zygote_,
526 #endif
527 base::Passed(&process_)));
528 }
529
530 // static
531 void ChildProcessLauncher::Context::SetProcessBackgroundedInternal(
532 base::Process process,
533 bool background) {
534 process.SetProcessBackgrounded(background);
535 #if defined(OS_ANDROID)
536 SetChildProcessInForeground(process.Handle(), !background);
537 #endif
538 }
539
540 // static
541 void ChildProcessLauncher::Context::TerminateInternal(
542 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
543 bool zygote,
544 #endif
545 base::Process process) {
546 #if defined(OS_ANDROID) 247 #if defined(OS_ANDROID)
547 VLOG(1) << "ChromeProcess: Stopping process with handle " 248 VLOG(1) << "ChromeProcess: Stopping process with handle "
548 << process.Handle(); 249 << process.Handle();
549 StopChildProcess(process.Handle()); 250 StopChildProcess(process.Handle());
550 #else 251 #else
551 // Client has gone away, so just kill the process. Using exit code 0 252 // Client has gone away, so just kill the process. Using exit code 0
552 // means that UMA won't treat this as a crash. 253 // means that UMA won't treat this as a crash.
553 process.Terminate(RESULT_CODE_NORMAL_EXIT, false); 254 process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
554 // On POSIX, we must additionally reap the child. 255 // On POSIX, we must additionally reap the child.
555 #if defined(OS_POSIX) 256 #if defined(OS_POSIX)
556 #if !defined(OS_MACOSX) 257 #if !defined(OS_MACOSX)
557 if (zygote) { 258 if (zygote) {
558 // If the renderer was created via a zygote, we have to proxy the reaping 259 // If the renderer was created via a zygote, we have to proxy the reaping
559 // through the zygote process. 260 // through the zygote process.
560 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle()); 261 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
561 } else 262 } else
562 #endif // !OS_MACOSX 263 #endif // !OS_MACOSX
563 base::EnsureProcessTerminated(process.Pass()); 264 base::EnsureProcessTerminated(process.Pass());
564 #endif // OS_POSIX 265 #endif // OS_POSIX
565 #endif // defined(OS_ANDROID) 266 #endif // defined(OS_ANDROID)
566 } 267 }
567 268
568 // ----------------------------------------------------------------------------- 269 void SetProcessBackgroundedOnLauncherThread(base::Process process,
270 bool background) {
271 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
272 process.SetProcessBackgrounded(background);
273 #if defined(OS_ANDROID)
274 SetChildProcessInForeground(process.Handle(), !background);
275 #endif
276 }
277
278 } // anonymous namespace
569 279
570 ChildProcessLauncher::ChildProcessLauncher( 280 ChildProcessLauncher::ChildProcessLauncher(
571 SandboxedProcessLauncherDelegate* delegate, 281 SandboxedProcessLauncherDelegate* delegate,
572 base::CommandLine* cmd_line, 282 base::CommandLine* cmd_line,
573 int child_process_id, 283 int child_process_id,
574 Client* client) { 284 Client* client,
575 context_ = new Context(); 285 bool terminate_on_shutdown)
576 context_->Launch( 286 : client_(client),
577 delegate, 287 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
578 cmd_line, 288 exit_code_(RESULT_CODE_NORMAL_EXIT),
579 child_process_id, 289 zygote_(false),
580 client); 290 starting_(true),
291 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
292 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
293 defined(UNDEFINED_SANITIZER)
294 terminate_child_on_shutdown_(false),
295 #else
296 terminate_child_on_shutdown_(terminate_on_shutdown),
297 #endif
298 weak_factory_(this) {
299 DCHECK(CalledOnValidThread());
300 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
301 Launch(delegate, cmd_line, child_process_id);
581 } 302 }
582 303
583 ChildProcessLauncher::~ChildProcessLauncher() { 304 ChildProcessLauncher::~ChildProcessLauncher() {
584 context_->ResetClient(); 305 DCHECK(CalledOnValidThread());
306 if (process_.IsValid() && terminate_child_on_shutdown_) {
307 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
308 // don't this on the UI/IO threads.
309 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
310 base::Bind(&TerminateOnLauncherThread, zygote_,
311 base::Passed(&process_)));
312 }
313 }
314
315 void ChildProcessLauncher::Launch(
316 SandboxedProcessLauncherDelegate* delegate,
317 base::CommandLine* cmd_line,
318 int child_process_id) {
319 DCHECK(CalledOnValidThread());
320
321 #if defined(OS_ANDROID)
322 // Android only supports renderer, sandboxed utility and gpu.
323 std::string process_type =
324 cmd_line->GetSwitchValueASCII(switches::kProcessType);
325 CHECK(process_type == switches::kGpuProcess ||
326 process_type == switches::kRendererProcess ||
327 process_type == switches::kUtilityProcess)
328 << "Unsupported process type: " << process_type;
329
330 // Non-sandboxed utility or renderer process are currently not supported.
331 DCHECK(process_type == switches::kGpuProcess ||
332 !cmd_line->HasSwitch(switches::kNoSandbox));
333
334 // We need to close the client end of the IPC channel to reliably detect
335 // child termination. We will close this fd after we create the child
336 // process which is asynchronous on Android.
337 base::ScopedFD ipcfd(delegate->TakeIpcFd().release());
338 #endif
339 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
340 weak_factory_.GetWeakPtr(),
341 terminate_child_on_shutdown_));
342 BrowserThread::PostTask(
343 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
344 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
345 child_process_id, delegate,
346 #if defined(OS_ANDROID)
347 base::Passed(&ipcfd),
348 #endif
349 cmd_line));
350 }
351
352 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
353 DCHECK(CalledOnValidThread());
354 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
355 if (zygote_) {
356 termination_status_ = ZygoteHostImpl::GetInstance()->
357 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
358 } else if (known_dead) {
359 termination_status_ =
360 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
361 } else {
362 #elif defined(OS_MACOSX)
363 if (known_dead) {
364 termination_status_ =
365 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
366 } else {
367 #elif defined(OS_ANDROID)
368 if (IsChildProcessOomProtected(process_.Handle())) {
369 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
370 } else {
371 #else
372 {
373 #endif
374 termination_status_ =
375 base::GetTerminationStatus(process_.Handle(), &exit_code_);
376 }
377 }
378
379 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
380 DCHECK(CalledOnValidThread());
381 base::Process to_pass = process_.Duplicate();
382 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
383 base::Bind(&SetProcessBackgroundedOnLauncherThread,
384 base::Passed(&to_pass), background));
385 }
386
387 void ChildProcessLauncher::DidLaunch(
388 base::WeakPtr<ChildProcessLauncher> instance,
389 bool terminate_on_shutdown,
390 bool zygote,
391 #if defined(OS_ANDROID)
392 base::ScopedFD ipcfd,
393 #endif
394 base::Process process) {
395 if (!process.IsValid())
396 LOG(ERROR) << "Failed to launch child process";
397
398 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
399 // is fixed.
400 tracked_objects::ScopedTracker tracking_profile1(
401 FROM_HERE_WITH_EXPLICIT_FUNCTION(
402 "465841 ChildProcessLauncher::Context::Notify::Start"));
403
404 if (instance.get()) {
405 instance->Notify(zygote,
406 #if defined(OS_ANDROID)
407 ipcfd.Pass(),
408 #endif
409 process.Pass());
410 } else {
411 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
412 // is fixed.
413 tracked_objects::ScopedTracker tracking_profile4(
414 FROM_HERE_WITH_EXPLICIT_FUNCTION(
415 "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
416 if (process.IsValid() && terminate_on_shutdown) {
417 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
418 // don't this on the UI/IO threads.
419 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
420 base::Bind(&TerminateOnLauncherThread, zygote,
421 base::Passed(&process)));
422 }
423 }
424 }
425
426 void ChildProcessLauncher::Notify(
427 bool zygote,
428 #if defined(OS_ANDROID)
429 base::ScopedFD ipcfd,
430 #endif
431 base::Process process) {
432 DCHECK(CalledOnValidThread());
433 starting_ = false;
434 process_ = process.Pass();
435
436 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
437 zygote_ = zygote;
438 #endif
439 if (process_.IsValid()) {
440 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
441 // is fixed.
442 tracked_objects::ScopedTracker tracking_profile2(
443 FROM_HERE_WITH_EXPLICIT_FUNCTION(
444 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
445 client_->OnProcessLaunched();
446 } else {
447 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
448 // is fixed.
449 tracked_objects::ScopedTracker tracking_profile3(
450 FROM_HERE_WITH_EXPLICIT_FUNCTION(
451 "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
452 client_->OnProcessLaunchFailed();
453 }
585 } 454 }
586 455
587 bool ChildProcessLauncher::IsStarting() { 456 bool ChildProcessLauncher::IsStarting() {
588 return context_->starting(); 457 // TODO(crbug.com/469248): This fails in some tests.
458 // DCHECK(CalledOnValidThread());
459 return starting_;
589 } 460 }
590 461
591 const base::Process& ChildProcessLauncher::GetProcess() const { 462 const base::Process& ChildProcessLauncher::GetProcess() const {
592 DCHECK(!context_->starting()); 463 // TODO(crbug.com/469248): This fails in some tests.
593 return context_->process(); 464 // DCHECK(CalledOnValidThread());
465 return process_;
594 } 466 }
595 467
596 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( 468 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
597 bool known_dead, 469 bool known_dead,
598 int* exit_code) { 470 int* exit_code) {
599 if (!context_->process().IsValid()) { 471 DCHECK(CalledOnValidThread());
472 if (!process_.IsValid()) {
600 // Process is already gone, so return the cached termination status. 473 // Process is already gone, so return the cached termination status.
601 if (exit_code) 474 if (exit_code)
602 *exit_code = context_->exit_code(); 475 *exit_code = exit_code_;
603 return context_->termination_status(); 476 return termination_status_;
604 } 477 }
605 478
606 context_->UpdateTerminationStatus(known_dead); 479 UpdateTerminationStatus(known_dead);
607 if (exit_code) 480 if (exit_code)
608 *exit_code = context_->exit_code(); 481 *exit_code = exit_code_;
609 482
610 // POSIX: If the process crashed, then the kernel closed the socket 483 // POSIX: If the process crashed, then the kernel closed the socket
611 // for it and so the child has already died by the time we get 484 // for it and so the child has already died by the time we get
612 // here. Since GetTerminationStatus called waitpid with WNOHANG, 485 // here. Since GetTerminationStatus called waitpid with WNOHANG,
613 // it'll reap the process. However, if GetTerminationStatus didn't 486 // it'll reap the process. However, if GetTerminationStatus didn't
614 // reap the child (because it was still running), we'll need to 487 // reap the child (because it was still running), we'll need to
615 // Terminate via ProcessWatcher. So we can't close the handle here. 488 // Terminate via ProcessWatcher. So we can't close the handle here.
616 if (context_->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING) 489 if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
617 context_->Close(); 490 process_.Close();
618 491
619 return context_->termination_status(); 492 return termination_status_;
620 }
621
622 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
623 context_->SetProcessBackgrounded(background);
624 }
625
626 void ChildProcessLauncher::SetTerminateChildOnShutdown(
627 bool terminate_on_shutdown) {
628 if (context_.get())
629 context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
630 } 493 }
631 494
632 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( 495 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
633 Client* client) { 496 Client* client) {
634 return context_->ReplaceClientForTest(client); 497 Client* ret = client_;
498 client_ = client;
499 return ret;
635 } 500 }
636 501
637 } // namespace content 502 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/child_process_launcher.h ('k') | content/browser/gpu/gpu_process_host.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698