OLD | NEW |
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. | 7 #include <utility> // For std::pair. |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 #include "content/browser/renderer_host/render_sandbox_host_linux.h" | 36 #include "content/browser/renderer_host/render_sandbox_host_linux.h" |
37 #include "content/browser/zygote_host/zygote_host_impl_linux.h" | 37 #include "content/browser/zygote_host/zygote_host_impl_linux.h" |
38 #endif | 38 #endif |
39 | 39 |
40 #if defined(OS_POSIX) | 40 #if defined(OS_POSIX) |
41 #include "base/posix/global_descriptors.h" | 41 #include "base/posix/global_descriptors.h" |
42 #endif | 42 #endif |
43 | 43 |
44 namespace content { | 44 namespace content { |
45 | 45 |
| 46 ChildProcessLauncher::~ChildProcessLauncher() {} |
| 47 |
| 48 class ChildProcessLauncherImpl : public ChildProcessLauncher { |
| 49 public: |
| 50 ChildProcessLauncherImpl( |
| 51 #if defined(OS_WIN) |
| 52 SandboxedProcessLauncherDelegate* delegate, |
| 53 #elif defined(OS_POSIX) |
| 54 bool use_zygote, |
| 55 const base::EnvironmentVector& environ, |
| 56 int ipcfd, |
| 57 #endif |
| 58 CommandLine* cmd_line, |
| 59 int child_process_id, |
| 60 Client* client); |
| 61 |
| 62 virtual ~ChildProcessLauncherImpl(); |
| 63 |
| 64 // ChildProcessLauncher implementation |
| 65 virtual bool IsStarting() OVERRIDE; |
| 66 virtual base::ProcessHandle GetHandle() OVERRIDE; |
| 67 virtual base::TerminationStatus GetChildTerminationStatus(bool known_dead, |
| 68 int* exit_code) |
| 69 OVERRIDE; |
| 70 virtual void SetProcessBackgrounded(bool background) OVERRIDE; |
| 71 virtual void SetTerminateChildOnShutdown(bool terminate_on_shutdown) OVERRIDE; |
| 72 |
| 73 private: |
| 74 class Context; |
| 75 |
| 76 scoped_refptr<Context> context_; |
| 77 |
| 78 DISALLOW_COPY_AND_ASSIGN(ChildProcessLauncherImpl); |
| 79 }; |
| 80 |
46 // Having the functionality of ChildProcessLauncher be in an internal | 81 // Having the functionality of ChildProcessLauncher be in an internal |
47 // ref counted object allows us to automatically terminate the process when the | 82 // ref counted object allows us to automatically terminate the process when the |
48 // parent class destructs, while still holding on to state that we need. | 83 // parent class destructs, while still holding on to state that we need. |
49 class ChildProcessLauncher::Context | 84 class ChildProcessLauncherImpl::Context |
50 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> { | 85 : public base::RefCountedThreadSafe<ChildProcessLauncherImpl::Context> { |
51 public: | 86 public: |
52 Context() | 87 Context() |
53 : client_(NULL), | 88 : client_(NULL), |
54 client_thread_id_(BrowserThread::UI), | 89 client_thread_id_(BrowserThread::UI), |
55 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION), | 90 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION), |
56 exit_code_(RESULT_CODE_NORMAL_EXIT), | 91 exit_code_(RESULT_CODE_NORMAL_EXIT), |
57 starting_(true) | 92 starting_(true) |
58 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 93 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
59 , zygote_(false) | 94 , zygote_(false) |
60 #endif | 95 #endif |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 const base::TimeTicks begin_launch_time, | 152 const base::TimeTicks begin_launch_time, |
118 base::ProcessHandle handle) { | 153 base::ProcessHandle handle) { |
119 RecordHistograms(begin_launch_time); | 154 RecordHistograms(begin_launch_time); |
120 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 155 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
121 // This is always invoked on the UI thread which is commonly the | 156 // This is always invoked on the UI thread which is commonly the |
122 // |client_thread_id| so we can shortcut one PostTask. | 157 // |client_thread_id| so we can shortcut one PostTask. |
123 this_object->Notify(handle); | 158 this_object->Notify(handle); |
124 } else { | 159 } else { |
125 BrowserThread::PostTask( | 160 BrowserThread::PostTask( |
126 client_thread_id, FROM_HERE, | 161 client_thread_id, FROM_HERE, |
127 base::Bind( | 162 base::Bind(&Context::Notify, this_object, handle)); |
128 &ChildProcessLauncher::Context::Notify, | |
129 this_object, | |
130 handle)); | |
131 } | 163 } |
132 } | 164 } |
133 #endif | 165 #endif |
134 | 166 |
135 void ResetClient() { | 167 void ResetClient() { |
136 // No need for locking as this function gets called on the same thread that | 168 // No need for locking as this function gets called on the same thread that |
137 // client_ would be used. | 169 // client_ would be used. |
138 CHECK(BrowserThread::CurrentlyOn(client_thread_id_)); | 170 CHECK(BrowserThread::CurrentlyOn(client_thread_id_)); |
139 client_ = NULL; | 171 client_ = NULL; |
140 } | 172 } |
141 | 173 |
142 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) { | 174 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) { |
143 terminate_child_on_shutdown_ = terminate_on_shutdown; | 175 terminate_child_on_shutdown_ = terminate_on_shutdown; |
144 } | 176 } |
145 | 177 |
146 private: | 178 private: |
147 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>; | 179 friend class base::RefCountedThreadSafe<Context>; |
148 friend class ChildProcessLauncher; | 180 friend class ChildProcessLauncherImpl; |
149 | 181 |
150 ~Context() { | 182 ~Context() { |
151 Terminate(); | 183 Terminate(); |
152 } | 184 } |
153 | 185 |
154 static void RecordHistograms(const base::TimeTicks begin_launch_time) { | 186 static void RecordHistograms(const base::TimeTicks begin_launch_time) { |
155 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 187 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
156 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) { | 188 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) { |
157 RecordLaunchHistograms(launch_time); | 189 RecordLaunchHistograms(launch_time); |
158 } else { | 190 } else { |
159 BrowserThread::PostTask( | 191 BrowserThread::PostTask( |
160 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 192 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
161 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms, | 193 base::Bind(&Context::RecordLaunchHistograms, |
162 launch_time)); | 194 launch_time)); |
163 } | 195 } |
164 } | 196 } |
165 | 197 |
166 static void RecordLaunchHistograms(const base::TimeDelta launch_time) { | 198 static void RecordLaunchHistograms(const base::TimeDelta launch_time) { |
167 // Log the launch time, separating out the first one (which will likely be | 199 // Log the launch time, separating out the first one (which will likely be |
168 // slower due to the rest of the browser initializing at the same time). | 200 // slower due to the rest of the browser initializing at the same time). |
169 static bool done_first_launch = false; | 201 static bool done_first_launch = false; |
170 if (done_first_launch) { | 202 if (done_first_launch) { |
171 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); | 203 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 std::vector<FileDescriptorInfo> files_to_register; | 238 std::vector<FileDescriptorInfo> files_to_register; |
207 files_to_register.push_back( | 239 files_to_register.push_back( |
208 FileDescriptorInfo(kPrimaryIPCChannel, | 240 FileDescriptorInfo(kPrimaryIPCChannel, |
209 base::FileDescriptor(ipcfd, false))); | 241 base::FileDescriptor(ipcfd, false))); |
210 | 242 |
211 GetContentClient()->browser()-> | 243 GetContentClient()->browser()-> |
212 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id, | 244 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id, |
213 &files_to_register); | 245 &files_to_register); |
214 | 246 |
215 StartChildProcess(cmd_line->argv(), files_to_register, | 247 StartChildProcess(cmd_line->argv(), files_to_register, |
216 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted, | 248 base::Bind(&Context::OnChildProcessStarted, |
217 this_object, client_thread_id, begin_launch_time)); | 249 this_object, client_thread_id, begin_launch_time)); |
218 | 250 |
219 #elif defined(OS_POSIX) | 251 #elif defined(OS_POSIX) |
220 base::ProcessHandle handle = base::kNullProcessHandle; | 252 base::ProcessHandle handle = base::kNullProcessHandle; |
221 // We need to close the client end of the IPC channel to reliably detect | 253 // We need to close the client end of the IPC channel to reliably detect |
222 // child termination. | 254 // child termination. |
223 file_util::ScopedFD ipcfd_closer(&ipcfd); | 255 file_util::ScopedFD ipcfd_closer(&ipcfd); |
224 | 256 |
225 std::string process_type = | 257 std::string process_type = |
226 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 258 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 bool terminate_child_on_shutdown_; | 434 bool terminate_child_on_shutdown_; |
403 #if defined(OS_ANDROID) | 435 #if defined(OS_ANDROID) |
404 // The fd to close after creating the process. | 436 // The fd to close after creating the process. |
405 int ipcfd_; | 437 int ipcfd_; |
406 #elif defined(OS_POSIX) && !defined(OS_MACOSX) | 438 #elif defined(OS_POSIX) && !defined(OS_MACOSX) |
407 bool zygote_; | 439 bool zygote_; |
408 #endif | 440 #endif |
409 }; | 441 }; |
410 | 442 |
411 | 443 |
412 ChildProcessLauncher::ChildProcessLauncher( | 444 ChildProcessLauncherImpl::ChildProcessLauncherImpl( |
413 #if defined(OS_WIN) | 445 #if defined(OS_WIN) |
414 SandboxedProcessLauncherDelegate* delegate, | 446 SandboxedProcessLauncherDelegate* delegate, |
415 #elif defined(OS_POSIX) | 447 #elif defined(OS_POSIX) |
416 bool use_zygote, | 448 bool use_zygote, |
417 const base::EnvironmentVector& environ, | 449 const base::EnvironmentVector& environ, |
418 int ipcfd, | 450 int ipcfd, |
419 #endif | 451 #endif |
420 CommandLine* cmd_line, | 452 CommandLine* cmd_line, |
421 int child_process_id, | 453 int child_process_id, |
422 Client* client) { | 454 Client* client) { |
423 context_ = new Context(); | 455 context_ = new Context(); |
424 context_->Launch( | 456 context_->Launch( |
425 #if defined(OS_WIN) | 457 #if defined(OS_WIN) |
426 delegate, | 458 delegate, |
427 #elif defined(OS_ANDROID) | 459 #elif defined(OS_ANDROID) |
428 ipcfd, | 460 ipcfd, |
429 #elif defined(OS_POSIX) | 461 #elif defined(OS_POSIX) |
430 use_zygote, | 462 use_zygote, |
431 environ, | 463 environ, |
432 ipcfd, | 464 ipcfd, |
433 #endif | 465 #endif |
434 cmd_line, | 466 cmd_line, |
435 child_process_id, | 467 child_process_id, |
436 client); | 468 client); |
437 } | 469 } |
438 | 470 |
439 ChildProcessLauncher::~ChildProcessLauncher() { | 471 ChildProcessLauncherImpl::~ChildProcessLauncherImpl() { |
440 context_->ResetClient(); | 472 context_->ResetClient(); |
441 } | 473 } |
442 | 474 |
443 bool ChildProcessLauncher::IsStarting() { | 475 bool ChildProcessLauncherImpl::IsStarting() { |
444 return context_->starting_; | 476 return context_->starting_; |
445 } | 477 } |
446 | 478 |
447 base::ProcessHandle ChildProcessLauncher::GetHandle() { | 479 base::ProcessHandle ChildProcessLauncherImpl::GetHandle() { |
448 DCHECK(!context_->starting_); | 480 DCHECK(!context_->starting_); |
449 return context_->process_.handle(); | 481 return context_->process_.handle(); |
450 } | 482 } |
451 | 483 |
452 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( | 484 base::TerminationStatus ChildProcessLauncherImpl::GetChildTerminationStatus( |
453 bool known_dead, | 485 bool known_dead, |
454 int* exit_code) { | 486 int* exit_code) { |
455 base::ProcessHandle handle = context_->process_.handle(); | 487 base::ProcessHandle handle = context_->process_.handle(); |
456 if (handle == base::kNullProcessHandle) { | 488 if (handle == base::kNullProcessHandle) { |
457 // Process is already gone, so return the cached termination status. | 489 // Process is already gone, so return the cached termination status. |
458 if (exit_code) | 490 if (exit_code) |
459 *exit_code = context_->exit_code_; | 491 *exit_code = context_->exit_code_; |
460 return context_->termination_status_; | 492 return context_->termination_status_; |
461 } | 493 } |
462 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 494 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
(...skipping 15 matching lines...) Expand all Loading... |
478 // here. Since GetTerminationStatus called waitpid with WNOHANG, | 510 // here. Since GetTerminationStatus called waitpid with WNOHANG, |
479 // it'll reap the process. However, if GetTerminationStatus didn't | 511 // it'll reap the process. However, if GetTerminationStatus didn't |
480 // reap the child (because it was still running), we'll need to | 512 // reap the child (because it was still running), we'll need to |
481 // Terminate via ProcessWatcher. So we can't close the handle here. | 513 // Terminate via ProcessWatcher. So we can't close the handle here. |
482 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING) | 514 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING) |
483 context_->process_.Close(); | 515 context_->process_.Close(); |
484 | 516 |
485 return context_->termination_status_; | 517 return context_->termination_status_; |
486 } | 518 } |
487 | 519 |
488 void ChildProcessLauncher::SetProcessBackgrounded(bool background) { | 520 void ChildProcessLauncherImpl::SetProcessBackgrounded(bool background) { |
489 BrowserThread::PostTask( | 521 BrowserThread::PostTask( |
490 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 522 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
491 base::Bind( | 523 base::Bind(&Context::SetProcessBackgrounded, GetHandle(), background)); |
492 &ChildProcessLauncher::Context::SetProcessBackgrounded, | |
493 GetHandle(), background)); | |
494 } | 524 } |
495 | 525 |
496 void ChildProcessLauncher::SetTerminateChildOnShutdown( | 526 void ChildProcessLauncherImpl::SetTerminateChildOnShutdown( |
497 bool terminate_on_shutdown) { | 527 bool terminate_on_shutdown) { |
498 if (context_.get()) | 528 if (context_.get()) |
499 context_->set_terminate_child_on_shutdown(terminate_on_shutdown); | 529 context_->set_terminate_child_on_shutdown(terminate_on_shutdown); |
500 } | 530 } |
501 | 531 |
| 532 scoped_ptr<ChildProcessLauncher> NewChildProcessLauncher( |
| 533 #if defined(OS_WIN) |
| 534 SandboxedProcessLauncherDelegate* delegate, |
| 535 #elif defined(OS_POSIX) |
| 536 bool use_zygote, |
| 537 const base::EnvironmentVector& environ, |
| 538 int ipcfd, |
| 539 #endif |
| 540 CommandLine* cmd_line, |
| 541 int child_process_id, |
| 542 ChildProcessLauncher::Client* client) { |
| 543 return scoped_ptr<ChildProcessLauncher>(new ChildProcessLauncherImpl( |
| 544 #if defined(OS_WIN) |
| 545 delegate, |
| 546 #elif defined(OS_POSIX) |
| 547 use_zygote, |
| 548 environ, |
| 549 ipcfd, |
| 550 #endif |
| 551 cmd_line, |
| 552 child_process_id, |
| 553 client)); |
| 554 } |
| 555 |
502 } // namespace content | 556 } // namespace content |
OLD | NEW |