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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 terminate_child_on_shutdown_(false) | 68 terminate_child_on_shutdown_(false) |
69 #else | 69 #else |
70 terminate_child_on_shutdown_(true) | 70 terminate_child_on_shutdown_(true) |
71 #endif | 71 #endif |
72 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 72 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
73 , zygote_(false) | 73 , zygote_(false) |
74 #endif | 74 #endif |
75 { | 75 { |
76 } | 76 } |
77 | 77 |
78 void Launch( | 78 void Launch(SandboxedProcessLauncherDelegate* delegate, |
79 SandboxedProcessLauncherDelegate* delegate, | 79 base::CommandLine* cmd_line, |
80 base::CommandLine* cmd_line, | 80 int child_process_id, |
81 int child_process_id, | 81 Client* client) { |
82 Client* client) { | |
83 client_ = client; | 82 client_ = client; |
84 | 83 |
85 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); | 84 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); |
86 | 85 |
87 #if defined(OS_ANDROID) | 86 #if defined(OS_ANDROID) |
88 // We need to close the client end of the IPC channel to reliably detect | 87 // We need to close the client end of the IPC channel to reliably detect |
89 // child termination. We will close this fd after we create the child | 88 // child termination. We will close this fd after we create the child |
90 // process which is asynchronous on Android. | 89 // process which is asynchronous on Android. |
91 ipcfd_ = delegate->GetIpcFd(); | 90 ipcfd_ = delegate->GetIpcFd(); |
92 #endif | 91 #endif |
93 BrowserThread::PostTask( | 92 BrowserThread::PostTask( |
94 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 93 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
95 base::Bind( | 94 base::Bind(&Context::LaunchInternal, |
96 &Context::LaunchInternal, | 95 make_scoped_refptr(this), |
97 make_scoped_refptr(this), | 96 client_thread_id_, |
98 client_thread_id_, | 97 child_process_id, |
99 child_process_id, | 98 delegate, |
100 delegate, | 99 cmd_line)); |
101 cmd_line)); | |
102 } | 100 } |
103 | 101 |
104 #if defined(OS_ANDROID) | 102 #if defined(OS_ANDROID) |
105 static void OnChildProcessStarted( | 103 static void OnChildProcessStarted( |
106 // |this_object| is NOT thread safe. Only use it to post a task back. | 104 // |this_object| is NOT thread safe. Only use it to post a task back. |
107 scoped_refptr<Context> this_object, | 105 scoped_refptr<Context> this_object, |
108 BrowserThread::ID client_thread_id, | 106 BrowserThread::ID client_thread_id, |
109 const base::TimeTicks begin_launch_time, | 107 const base::TimeTicks begin_launch_time, |
110 base::ProcessHandle handle) { | 108 base::ProcessHandle handle) { |
111 RecordHistograms(begin_launch_time); | 109 RecordHistograms(begin_launch_time); |
112 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 110 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
113 // This is always invoked on the UI thread which is commonly the | 111 // This is always invoked on the UI thread which is commonly the |
114 // |client_thread_id| so we can shortcut one PostTask. | 112 // |client_thread_id| so we can shortcut one PostTask. |
115 this_object->Notify(handle); | 113 this_object->Notify(base::ProcessObject(handle)); |
scottmg
2014/10/14 18:51:03
I'm a little worried that it's going to be difficu
rvargas (doing something else)
2014/10/14 19:56:54
The problem is that restricting the behavior impli
| |
116 } else { | 114 } else { |
117 BrowserThread::PostTask( | 115 BrowserThread::PostTask( |
118 client_thread_id, FROM_HERE, | 116 client_thread_id, FROM_HERE, |
119 base::Bind( | 117 base::Bind( |
120 &ChildProcessLauncher::Context::Notify, | 118 &ChildProcessLauncher::Context::Notify, |
121 this_object, | 119 this_object, |
122 handle)); | 120 base::Passed(base::ProcessObject(handle)))); |
123 } | 121 } |
124 } | 122 } |
125 #endif | 123 #endif |
126 | 124 |
127 void ResetClient() { | 125 void ResetClient() { |
128 // No need for locking as this function gets called on the same thread that | 126 // No need for locking as this function gets called on the same thread that |
129 // client_ would be used. | 127 // client_ would be used. |
130 CHECK(BrowserThread::CurrentlyOn(client_thread_id_)); | 128 CHECK(BrowserThread::CurrentlyOn(client_thread_id_)); |
131 client_ = NULL; | 129 client_ = NULL; |
132 } | 130 } |
133 | 131 |
134 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) { | 132 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) { |
135 terminate_child_on_shutdown_ = terminate_on_shutdown; | 133 terminate_child_on_shutdown_ = terminate_on_shutdown; |
136 } | 134 } |
137 | 135 |
136 void GetTerminationStatus() { | |
137 termination_status_ = | |
138 base::GetTerminationStatus(process_.Handle(), &exit_code_); | |
139 } | |
140 | |
141 void SetProcessBackgrounded(bool background) { | |
142 base::ProcessObject to_pass = process_.Duplicate(); | |
143 BrowserThread::PostTask( | |
144 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | |
145 base::Bind(&Context::SetProcessBackgroundedInternal, | |
146 base::Passed(&to_pass), background)); | |
147 } | |
148 | |
138 private: | 149 private: |
139 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>; | 150 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>; |
140 friend class ChildProcessLauncher; | 151 friend class ChildProcessLauncher; |
141 | 152 |
142 ~Context() { | 153 ~Context() { |
143 Terminate(); | 154 Terminate(); |
144 } | 155 } |
145 | 156 |
146 static void RecordHistograms(const base::TimeTicks begin_launch_time) { | 157 static void RecordHistograms(const base::TimeTicks begin_launch_time) { |
147 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 158 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 if (handle) | 327 if (handle) |
317 RecordHistograms(begin_launch_time); | 328 RecordHistograms(begin_launch_time); |
318 BrowserThread::PostTask( | 329 BrowserThread::PostTask( |
319 client_thread_id, FROM_HERE, | 330 client_thread_id, FROM_HERE, |
320 base::Bind( | 331 base::Bind( |
321 &Context::Notify, | 332 &Context::Notify, |
322 this_object.get(), | 333 this_object.get(), |
323 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 334 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
324 use_zygote, | 335 use_zygote, |
325 #endif | 336 #endif |
326 handle)); | 337 base::Passed(base::ProcessObject(handle)))); |
327 #endif // !defined(OS_ANDROID) | 338 #endif // !defined(OS_ANDROID) |
328 } | 339 } |
329 | 340 |
330 void Notify( | 341 void Notify( |
331 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 342 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
332 bool zygote, | 343 bool zygote, |
333 #endif | 344 #endif |
334 base::ProcessHandle handle) { | 345 base::ProcessObject process) { |
335 #if defined(OS_ANDROID) | 346 #if defined(OS_ANDROID) |
336 // Finally close the ipcfd | 347 // Finally close the ipcfd |
337 base::ScopedFD ipcfd_closer(ipcfd_); | 348 base::ScopedFD ipcfd_closer(ipcfd_); |
338 #endif | 349 #endif |
339 starting_ = false; | 350 starting_ = false; |
340 process_.set_handle(handle); | 351 process_ = process.Pass(); |
341 if (!handle) | 352 if (!process_.IsValid()) |
342 LOG(ERROR) << "Failed to launch child process"; | 353 LOG(ERROR) << "Failed to launch child process"; |
343 | 354 |
344 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 355 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
345 zygote_ = zygote; | 356 zygote_ = zygote; |
346 #endif | 357 #endif |
347 if (client_) { | 358 if (client_) { |
348 if (handle) { | 359 if (process_.IsValid()) { |
349 client_->OnProcessLaunched(); | 360 client_->OnProcessLaunched(); |
350 } else { | 361 } else { |
351 client_->OnProcessLaunchFailed(); | 362 client_->OnProcessLaunchFailed(); |
352 } | 363 } |
353 } else { | 364 } else { |
354 Terminate(); | 365 Terminate(); |
355 } | 366 } |
356 } | 367 } |
357 | 368 |
358 void Terminate() { | 369 void Terminate() { |
359 if (!process_.handle()) | 370 if (!process_.IsValid()) |
360 return; | 371 return; |
361 | 372 |
362 if (!terminate_child_on_shutdown_) | 373 if (!terminate_child_on_shutdown_) |
363 return; | 374 return; |
364 | 375 |
365 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So | 376 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
366 // don't this on the UI/IO threads. | 377 // don't this on the UI/IO threads. |
367 BrowserThread::PostTask( | 378 BrowserThread::PostTask( |
368 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 379 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
369 base::Bind( | 380 base::Bind( |
370 &Context::TerminateInternal, | 381 &Context::TerminateInternal, |
371 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 382 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
372 zygote_, | 383 zygote_, |
373 #endif | 384 #endif |
374 process_.handle())); | 385 base::Passed(&process_))); |
375 process_.set_handle(base::kNullProcessHandle); | |
376 } | 386 } |
377 | 387 |
378 static void SetProcessBackgrounded(base::ProcessHandle handle, | 388 static void SetProcessBackgroundedInternal(base::ProcessObject process, |
379 bool background) { | 389 bool background) { |
380 base::Process process(handle); | |
381 process.SetProcessBackgrounded(background); | 390 process.SetProcessBackgrounded(background); |
382 #if defined(OS_ANDROID) | 391 #if defined(OS_ANDROID) |
383 SetChildProcessInForeground(handle, !background); | 392 SetChildProcessInForeground(process.Handle(), !background); |
384 #endif | 393 #endif |
385 } | 394 } |
386 | 395 |
387 static void TerminateInternal( | 396 static void TerminateInternal( |
388 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 397 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
389 bool zygote, | 398 bool zygote, |
390 #endif | 399 #endif |
391 base::ProcessHandle handle) { | 400 base::ProcessObject process) { |
392 #if defined(OS_ANDROID) | 401 #if defined(OS_ANDROID) |
393 VLOG(0) << "ChromeProcess: Stopping process with handle " << handle; | 402 VLOG(1) << "ChromeProcess: Stopping process with handle " |
394 StopChildProcess(handle); | 403 << process.Handle(); |
404 StopChildProcess(process.Handle()); | |
395 #else | 405 #else |
396 base::Process process(handle); | |
397 // Client has gone away, so just kill the process. Using exit code 0 | 406 // Client has gone away, so just kill the process. Using exit code 0 |
398 // means that UMA won't treat this as a crash. | 407 // means that UMA won't treat this as a crash. |
399 process.Terminate(RESULT_CODE_NORMAL_EXIT); | 408 process.Terminate(RESULT_CODE_NORMAL_EXIT); |
400 // On POSIX, we must additionally reap the child. | 409 // On POSIX, we must additionally reap the child. |
401 #if defined(OS_POSIX) | 410 #if defined(OS_POSIX) |
402 #if !defined(OS_MACOSX) | 411 #if !defined(OS_MACOSX) |
403 if (zygote) { | 412 if (zygote) { |
404 // If the renderer was created via a zygote, we have to proxy the reaping | 413 // If the renderer was created via a zygote, we have to proxy the reaping |
405 // through the zygote process. | 414 // through the zygote process. |
406 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle); | 415 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle()); |
407 } else | 416 } else |
408 #endif // !OS_MACOSX | 417 #endif // !OS_MACOSX |
409 { | 418 { |
410 base::EnsureProcessTerminated(handle); | 419 base::EnsureProcessTerminated(process.Handle()); |
411 } | 420 } |
412 #endif // OS_POSIX | 421 #endif // OS_POSIX |
413 process.Close(); | |
414 #endif // defined(OS_ANDROID) | 422 #endif // defined(OS_ANDROID) |
415 } | 423 } |
416 | 424 |
417 Client* client_; | 425 Client* client_; |
418 BrowserThread::ID client_thread_id_; | 426 BrowserThread::ID client_thread_id_; |
419 base::Process process_; | 427 base::ProcessObject process_; |
420 base::TerminationStatus termination_status_; | 428 base::TerminationStatus termination_status_; |
421 int exit_code_; | 429 int exit_code_; |
422 bool starting_; | 430 bool starting_; |
423 // Controls whether the child process should be terminated on browser | 431 // Controls whether the child process should be terminated on browser |
424 // shutdown. Default behavior is to terminate the child. | 432 // shutdown. Default behavior is to terminate the child. |
425 bool terminate_child_on_shutdown_; | 433 bool terminate_child_on_shutdown_; |
426 #if defined(OS_ANDROID) | 434 #if defined(OS_ANDROID) |
427 // The fd to close after creating the process. | 435 // The fd to close after creating the process. |
428 int ipcfd_; | 436 int ipcfd_; |
429 #elif defined(OS_POSIX) && !defined(OS_MACOSX) | 437 #elif defined(OS_POSIX) && !defined(OS_MACOSX) |
(...skipping 16 matching lines...) Expand all Loading... | |
446 } | 454 } |
447 | 455 |
448 ChildProcessLauncher::~ChildProcessLauncher() { | 456 ChildProcessLauncher::~ChildProcessLauncher() { |
449 context_->ResetClient(); | 457 context_->ResetClient(); |
450 } | 458 } |
451 | 459 |
452 bool ChildProcessLauncher::IsStarting() { | 460 bool ChildProcessLauncher::IsStarting() { |
453 return context_->starting_; | 461 return context_->starting_; |
454 } | 462 } |
455 | 463 |
456 base::ProcessHandle ChildProcessLauncher::GetHandle() { | 464 const base::ProcessObject& ChildProcessLauncher::GetProcess() const { |
457 DCHECK(!context_->starting_); | 465 DCHECK(!context_->starting_); |
458 return context_->process_.handle(); | 466 return context_->process_; |
459 } | 467 } |
460 | 468 |
461 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( | 469 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( |
462 bool known_dead, | 470 bool known_dead, |
463 int* exit_code) { | 471 int* exit_code) { |
464 base::ProcessHandle handle = context_->process_.handle(); | 472 if (!context_->process_.IsValid()) { |
465 if (handle == base::kNullProcessHandle) { | |
466 // Process is already gone, so return the cached termination status. | 473 // Process is already gone, so return the cached termination status. |
467 if (exit_code) | 474 if (exit_code) |
468 *exit_code = context_->exit_code_; | 475 *exit_code = context_->exit_code_; |
469 return context_->termination_status_; | 476 return context_->termination_status_; |
470 } | 477 } |
471 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 478 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
472 if (context_->zygote_) { | 479 if (context_->zygote_) { |
473 context_->termination_status_ = ZygoteHostImpl::GetInstance()-> | 480 context_->termination_status_ = ZygoteHostImpl::GetInstance()-> |
474 GetTerminationStatus(handle, known_dead, &context_->exit_code_); | 481 GetTerminationStatus(context_->process_.Handle(), known_dead, |
482 &context_->exit_code_); | |
475 } else if (known_dead) { | 483 } else if (known_dead) { |
476 context_->termination_status_ = | 484 context_->termination_status_ = |
477 base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_); | 485 base::GetKnownDeadTerminationStatus(context_->process_.Handle(), |
486 &context_->exit_code_); | |
478 } else { | 487 } else { |
479 #elif defined(OS_MACOSX) | 488 #elif defined(OS_MACOSX) |
480 if (known_dead) { | 489 if (known_dead) { |
481 context_->termination_status_ = | 490 context_->termination_status_ = |
482 base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_); | 491 base::GetKnownDeadTerminationStatus(context_->process_.Handle(), |
492 &context_->exit_code_); | |
483 } else { | 493 } else { |
484 #elif defined(OS_ANDROID) | 494 #elif defined(OS_ANDROID) |
485 if (IsChildProcessOomProtected(handle)) { | 495 if (IsChildProcessOomProtected(context_->process_.Handle())) { |
486 context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED; | 496 context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED; |
487 } else { | 497 } else { |
488 #else | 498 #else |
489 { | 499 { |
490 #endif | 500 #endif |
491 context_->termination_status_ = | 501 context_->GetTerminationStatus(); |
492 base::GetTerminationStatus(handle, &context_->exit_code_); | |
493 } | 502 } |
494 | 503 |
495 if (exit_code) | 504 if (exit_code) |
496 *exit_code = context_->exit_code_; | 505 *exit_code = context_->exit_code_; |
497 | 506 |
498 // POSIX: If the process crashed, then the kernel closed the socket | 507 // POSIX: If the process crashed, then the kernel closed the socket |
499 // for it and so the child has already died by the time we get | 508 // for it and so the child has already died by the time we get |
500 // here. Since GetTerminationStatus called waitpid with WNOHANG, | 509 // here. Since GetTerminationStatus called waitpid with WNOHANG, |
501 // it'll reap the process. However, if GetTerminationStatus didn't | 510 // it'll reap the process. However, if GetTerminationStatus didn't |
502 // reap the child (because it was still running), we'll need to | 511 // reap the child (because it was still running), we'll need to |
503 // Terminate via ProcessWatcher. So we can't close the handle here. | 512 // Terminate via ProcessWatcher. So we can't close the handle here. |
504 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING) | 513 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING) |
505 context_->process_.Close(); | 514 context_->process_.Close(); |
506 | 515 |
507 return context_->termination_status_; | 516 return context_->termination_status_; |
508 } | 517 } |
509 | 518 |
510 void ChildProcessLauncher::SetProcessBackgrounded(bool background) { | 519 void ChildProcessLauncher::SetProcessBackgrounded(bool background) { |
511 BrowserThread::PostTask( | 520 context_->process_.SetProcessBackgrounded(background); |
512 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | |
513 base::Bind( | |
514 &ChildProcessLauncher::Context::SetProcessBackgrounded, | |
515 GetHandle(), background)); | |
516 } | 521 } |
517 | 522 |
518 void ChildProcessLauncher::SetTerminateChildOnShutdown( | 523 void ChildProcessLauncher::SetTerminateChildOnShutdown( |
519 bool terminate_on_shutdown) { | 524 bool terminate_on_shutdown) { |
520 if (context_.get()) | 525 if (context_.get()) |
521 context_->set_terminate_child_on_shutdown(terminate_on_shutdown); | 526 context_->set_terminate_child_on_shutdown(terminate_on_shutdown); |
522 } | 527 } |
523 | 528 |
524 } // namespace content | 529 } // namespace content |
OLD | NEW |