| 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 |