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

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

Issue 651253002: Enforce handle ownership in base::Process (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add empty line Created 6 years, 2 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
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. 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
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::Process(handle));
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::Process(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::Process 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
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::Process(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::Process 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::Process 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::Process 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::Process 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
(...skipping 22 matching lines...) Expand all
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::Process& 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
OLDNEW
« no previous file with comments | « content/browser/child_process_launcher.h ('k') | content/browser/fileapi/fileapi_message_filter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698