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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 // |this_object| is NOT thread safe. Only use it to post a task back. | 71 // |this_object| is NOT thread safe. Only use it to post a task back. |
72 scoped_refptr<Context> this_object, | 72 scoped_refptr<Context> this_object, |
73 BrowserThread::ID client_thread_id, | 73 BrowserThread::ID client_thread_id, |
74 const base::TimeTicks begin_launch_time, | 74 const base::TimeTicks begin_launch_time, |
75 base::ProcessHandle handle); | 75 base::ProcessHandle handle); |
76 #endif | 76 #endif |
77 | 77 |
78 // Resets the client (the client is going away). | 78 // Resets the client (the client is going away). |
79 void ResetClient(); | 79 void ResetClient(); |
80 | 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 |
81 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) { | 91 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) { |
82 terminate_child_on_shutdown_ = terminate_on_shutdown; | 92 terminate_child_on_shutdown_ = terminate_on_shutdown; |
83 } | 93 } |
84 | 94 |
85 void GetTerminationStatus() { | 95 void UpdateTerminationStatus(bool known_dead); |
86 termination_status_ = | 96 |
87 base::GetTerminationStatus(process_.Handle(), &exit_code_); | 97 void Close() { process_.Close(); } |
88 } | |
89 | 98 |
90 void SetProcessBackgrounded(bool background); | 99 void SetProcessBackgrounded(bool background); |
91 | 100 |
92 private: | 101 private: |
93 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>; | 102 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>; |
94 friend class ChildProcessLauncher; | |
95 | 103 |
96 ~Context() { | 104 ~Context() { |
97 Terminate(); | 105 Terminate(); |
98 } | 106 } |
99 | 107 |
100 static void RecordHistograms(base::TimeTicks begin_launch_time); | 108 static void RecordHistograms(base::TimeTicks begin_launch_time); |
101 static void RecordLaunchHistograms(base::TimeDelta launch_time); | 109 static void RecordLaunchHistograms(base::TimeDelta launch_time); |
102 | 110 |
103 // Performs the actual work of launching the process. | 111 // Performs the actual work of launching the process. |
104 // Runs on the PROCESS_LAUNCHER thread. | 112 // Runs on the PROCESS_LAUNCHER thread. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 } | 219 } |
212 #endif | 220 #endif |
213 | 221 |
214 void ChildProcessLauncher::Context::ResetClient() { | 222 void ChildProcessLauncher::Context::ResetClient() { |
215 // No need for locking as this function gets called on the same thread that | 223 // No need for locking as this function gets called on the same thread that |
216 // client_ would be used. | 224 // client_ would be used. |
217 CHECK(BrowserThread::CurrentlyOn(client_thread_id_)); | 225 CHECK(BrowserThread::CurrentlyOn(client_thread_id_)); |
218 client_ = NULL; | 226 client_ = NULL; |
219 } | 227 } |
220 | 228 |
| 229 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead) { |
| 230 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 231 if (zygote_) { |
| 232 termination_status_ = ZygoteHostImpl::GetInstance()-> |
| 233 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_); |
| 234 } else if (known_dead) { |
| 235 termination_status_ = |
| 236 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); |
| 237 } else { |
| 238 #elif defined(OS_MACOSX) |
| 239 if (known_dead) { |
| 240 termination_status_ = |
| 241 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); |
| 242 } else { |
| 243 #elif defined(OS_ANDROID) |
| 244 if (IsChildProcessOomProtected(process_.Handle())) { |
| 245 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED; |
| 246 } else { |
| 247 #else |
| 248 { |
| 249 #endif |
| 250 termination_status_ = |
| 251 base::GetTerminationStatus(process_.Handle(), &exit_code_); |
| 252 } |
| 253 } |
| 254 |
221 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background) { | 255 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background) { |
222 base::Process to_pass = process_.Duplicate(); | 256 base::Process to_pass = process_.Duplicate(); |
223 BrowserThread::PostTask( | 257 BrowserThread::PostTask( |
224 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 258 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
225 base::Bind(&Context::SetProcessBackgroundedInternal, | 259 base::Bind(&Context::SetProcessBackgroundedInternal, |
226 base::Passed(&to_pass), background)); | 260 base::Passed(&to_pass), background)); |
227 } | 261 } |
228 | 262 |
229 // static | 263 // static |
230 void ChildProcessLauncher::Context::RecordHistograms( | 264 void ChildProcessLauncher::Context::RecordHistograms( |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
514 cmd_line, | 548 cmd_line, |
515 child_process_id, | 549 child_process_id, |
516 client); | 550 client); |
517 } | 551 } |
518 | 552 |
519 ChildProcessLauncher::~ChildProcessLauncher() { | 553 ChildProcessLauncher::~ChildProcessLauncher() { |
520 context_->ResetClient(); | 554 context_->ResetClient(); |
521 } | 555 } |
522 | 556 |
523 bool ChildProcessLauncher::IsStarting() { | 557 bool ChildProcessLauncher::IsStarting() { |
524 return context_->starting_; | 558 return context_->starting(); |
525 } | 559 } |
526 | 560 |
527 const base::Process& ChildProcessLauncher::GetProcess() const { | 561 const base::Process& ChildProcessLauncher::GetProcess() const { |
528 DCHECK(!context_->starting_); | 562 DCHECK(!context_->starting()); |
529 return context_->process_; | 563 return context_->process(); |
530 } | 564 } |
531 | 565 |
532 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( | 566 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( |
533 bool known_dead, | 567 bool known_dead, |
534 int* exit_code) { | 568 int* exit_code) { |
535 if (!context_->process_.IsValid()) { | 569 if (!context_->process().IsValid()) { |
536 // Process is already gone, so return the cached termination status. | 570 // Process is already gone, so return the cached termination status. |
537 if (exit_code) | 571 if (exit_code) |
538 *exit_code = context_->exit_code_; | 572 *exit_code = context_->exit_code(); |
539 return context_->termination_status_; | 573 return context_->termination_status(); |
540 } | |
541 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | |
542 if (context_->zygote_) { | |
543 context_->termination_status_ = ZygoteHostImpl::GetInstance()-> | |
544 GetTerminationStatus(context_->process_.Handle(), known_dead, | |
545 &context_->exit_code_); | |
546 } else if (known_dead) { | |
547 context_->termination_status_ = | |
548 base::GetKnownDeadTerminationStatus(context_->process_.Handle(), | |
549 &context_->exit_code_); | |
550 } else { | |
551 #elif defined(OS_MACOSX) | |
552 if (known_dead) { | |
553 context_->termination_status_ = | |
554 base::GetKnownDeadTerminationStatus(context_->process_.Handle(), | |
555 &context_->exit_code_); | |
556 } else { | |
557 #elif defined(OS_ANDROID) | |
558 if (IsChildProcessOomProtected(context_->process_.Handle())) { | |
559 context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED; | |
560 } else { | |
561 #else | |
562 { | |
563 #endif | |
564 context_->GetTerminationStatus(); | |
565 } | 574 } |
566 | 575 |
| 576 context_->UpdateTerminationStatus(known_dead); |
567 if (exit_code) | 577 if (exit_code) |
568 *exit_code = context_->exit_code_; | 578 *exit_code = context_->exit_code(); |
569 | 579 |
570 // POSIX: If the process crashed, then the kernel closed the socket | 580 // POSIX: If the process crashed, then the kernel closed the socket |
571 // for it and so the child has already died by the time we get | 581 // for it and so the child has already died by the time we get |
572 // here. Since GetTerminationStatus called waitpid with WNOHANG, | 582 // here. Since GetTerminationStatus called waitpid with WNOHANG, |
573 // it'll reap the process. However, if GetTerminationStatus didn't | 583 // it'll reap the process. However, if GetTerminationStatus didn't |
574 // reap the child (because it was still running), we'll need to | 584 // reap the child (because it was still running), we'll need to |
575 // Terminate via ProcessWatcher. So we can't close the handle here. | 585 // Terminate via ProcessWatcher. So we can't close the handle here. |
576 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING) | 586 if (context_->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING) |
577 context_->process_.Close(); | 587 context_->Close(); |
578 | 588 |
579 return context_->termination_status_; | 589 return context_->termination_status(); |
580 } | 590 } |
581 | 591 |
582 void ChildProcessLauncher::SetProcessBackgrounded(bool background) { | 592 void ChildProcessLauncher::SetProcessBackgrounded(bool background) { |
583 context_->SetProcessBackgrounded(background); | 593 context_->SetProcessBackgrounded(background); |
584 } | 594 } |
585 | 595 |
586 void ChildProcessLauncher::SetTerminateChildOnShutdown( | 596 void ChildProcessLauncher::SetTerminateChildOnShutdown( |
587 bool terminate_on_shutdown) { | 597 bool terminate_on_shutdown) { |
588 if (context_.get()) | 598 if (context_.get()) |
589 context_->set_terminate_child_on_shutdown(terminate_on_shutdown); | 599 context_->set_terminate_child_on_shutdown(terminate_on_shutdown); |
590 } | 600 } |
591 | 601 |
592 } // namespace content | 602 } // namespace content |
OLD | NEW |