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

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

Issue 16267002: Re-fix http://crbug.com/87176, and add a test. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase on top of https://codereview.chromium.org/16490003/ Created 7 years, 6 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 | Annotate | Revision Log
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 25 matching lines...) Expand all
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698