blob: 23cf832e6652d9ab198cb85b7749bcdcc4aeda9c [file] [log] [blame]
shrike8fbe9d32015-06-02 19:53:571// Copyright 2012 The Chromium Authors. All rights reserved.
[email protected]9610ef242009-11-18 02:41:262// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]df8e899b2011-02-22 22:58:225#include "content/browser/child_process_launcher.h"
[email protected]9610ef242009-11-18 02:41:266
[email protected]037edb52011-11-15 21:14:067#include "base/bind.h"
[email protected]9610ef242009-11-18 02:41:268#include "base/command_line.h"
thestigb7aad54f2014-09-05 18:25:399#include "base/files/file_util.h"
[email protected]9610ef242009-11-18 02:41:2610#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1511#include "base/memory/scoped_ptr.h"
[email protected]323fdc312013-02-25 18:44:2612#include "base/metrics/histogram.h"
[email protected]dd4b51262013-07-25 21:38:2313#include "base/process/process.h"
erikchen8054a8c2015-03-11 02:34:2914#include "base/profiler/scoped_tracker.h"
[email protected]20305ec2011-01-21 04:55:5215#include "base/synchronization/lock.h"
[email protected]34b99632011-01-01 01:01:0616#include "base/threading/thread.h"
[email protected]87f3c082011-10-19 18:07:4417#include "content/public/browser/content_browser_client.h"
[email protected]b3aabd342012-06-04 19:33:5618#include "content/public/common/content_descriptors.h"
[email protected]c08950d22011-10-13 22:20:2919#include "content/public/common/content_switches.h"
[email protected]b39ef1cb2011-10-25 04:46:5520#include "content/public/common/result_codes.h"
[email protected]121e61382014-03-13 11:35:1521#include "content/public/common/sandboxed_process_launcher_delegate.h"
[email protected]9610ef242009-11-18 02:41:2622
23#if defined(OS_WIN)
[email protected]57999812013-02-24 05:40:5224#include "base/files/file_path.h"
[email protected]34f48682013-03-20 00:30:1825#include "content/common/sandbox_win.h"
[email protected]e25b04c92012-10-23 20:05:0626#include "content/public/common/sandbox_init.h"
[email protected]e63c4d72011-05-31 22:38:2927#elif defined(OS_MACOSX)
[email protected]f5bcd0f2014-06-10 14:50:4128#include "content/browser/bootstrap_sandbox_mac.h"
[email protected]ed0fbe62011-06-23 18:32:1129#include "content/browser/mach_broker_mac.h"
[email protected]f5bcd0f2014-06-10 14:50:4130#include "sandbox/mac/bootstrap_sandbox.h"
[email protected]30935362012-06-28 21:26:2331#elif defined(OS_ANDROID)
32#include "base/android/jni_android.h"
[email protected]5e44a142013-03-19 09:48:3933#include "content/browser/android/child_process_launcher_android.h"
[email protected]e63c4d72011-05-31 22:38:2934#elif defined(OS_POSIX)
[email protected]87fc6b52013-10-16 11:59:2935#include "base/memory/shared_memory.h"
[email protected]3b63f8f42011-03-28 01:54:1536#include "base/memory/singleton.h"
[email protected]a01efd22011-03-01 00:38:3237#include "content/browser/renderer_host/render_sandbox_host_linux.h"
[email protected]13d6b3c2012-07-24 01:31:3138#include "content/browser/zygote_host/zygote_host_impl_linux.h"
[email protected]a0c900e2013-09-11 18:16:1039#include "content/common/child_process_sandbox_support_impl_linux.h"
[email protected]9610ef242009-11-18 02:41:2640#endif
41
[email protected]fb1277e82009-11-21 20:32:3042#if defined(OS_POSIX)
[email protected]613eef62012-11-09 23:46:5443#include "base/posix/global_descriptors.h"
morritad95714f2014-10-01 02:37:2444#include "content/browser/file_descriptor_info_impl.h"
[email protected]fb1277e82009-11-21 20:32:3045#endif
46
[email protected]130757672012-10-24 00:26:1947namespace content {
[email protected]631bb742011-11-02 11:29:3948
sievers954e37a2015-03-28 01:50:2449namespace {
[email protected]9610ef242009-11-18 02:41:2650
sievers954e37a2015-03-28 01:50:2451typedef base::Callback<void(bool,
tkentdd53cf7322015-03-23 00:54:5052#if defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:2453 base::ScopedFD,
tkentdd53cf7322015-03-23 00:54:5054#endif
sievers954e37a2015-03-28 01:50:2455 base::Process)> NotifyCallback;
tkentdd53cf7322015-03-23 00:54:5056
sievers954e37a2015-03-28 01:50:2457void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
58 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:2359 // Log the launch time, separating out the first one (which will likely be
60 // slower due to the rest of the browser initializing at the same time).
61 static bool done_first_launch = false;
62 if (done_first_launch) {
63 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
64 } else {
65 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
66 done_first_launch = true;
67 }
68}
69
sievers954e37a2015-03-28 01:50:2470#if defined(OS_ANDROID)
71// TODO(sievers): Remove this by defining better what happens on what
72// thread in the corresponding Java code.
73void OnChildProcessStartedAndroid(const NotifyCallback& callback,
74 BrowserThread::ID client_thread_id,
75 const base::TimeTicks begin_launch_time,
76 base::ScopedFD ipcfd,
77 base::ProcessHandle handle) {
78 // This can be called on the launcher thread or UI thread.
79 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
80 BrowserThread::PostTask(
81 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
82 base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
83
84 base::Closure callback_on_client_thread(
85 base::Bind(callback, false, base::Passed(&ipcfd),
86 base::Passed(base::Process(handle))));
87 if (BrowserThread::CurrentlyOn(client_thread_id)) {
88 callback_on_client_thread.Run();
89 } else {
90 BrowserThread::PostTask(
91 client_thread_id, FROM_HERE, callback_on_client_thread);
92 }
93}
94#endif
95
96void LaunchOnLauncherThread(const NotifyCallback& callback,
97 BrowserThread::ID client_thread_id,
98 int child_process_id,
99 SandboxedProcessLauncherDelegate* delegate,
100#if defined(OS_ANDROID)
101 base::ScopedFD ipcfd,
102#endif
103 base::CommandLine* cmd_line) {
104 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:23105 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
106#if defined(OS_WIN)
sievers954e37a2015-03-28 01:50:24107 bool use_zygote = false;
rvargas7951bf62014-11-14 04:09:23108 bool launch_elevated = delegate->ShouldLaunchElevated();
rvargas7951bf62014-11-14 04:09:23109#elif defined(OS_MACOSX)
sievers954e37a2015-03-28 01:50:24110 bool use_zygote = false;
rvargas7951bf62014-11-14 04:09:23111 base::EnvironmentMap env = delegate->GetEnvironment();
112 base::ScopedFD ipcfd = delegate->TakeIpcFd();
sievers954e37a2015-03-28 01:50:24113#elif defined(OS_POSIX) && !defined(OS_ANDROID)
rvargas7951bf62014-11-14 04:09:23114 bool use_zygote = delegate->ShouldUseZygote();
115 base::EnvironmentMap env = delegate->GetEnvironment();
116 base::ScopedFD ipcfd = delegate->TakeIpcFd();
117#endif
118 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
119 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
120
rvargas3e5d4452014-11-24 19:30:02121 base::Process process;
rvargas0bf966a2015-01-10 04:16:33122#if defined(OS_WIN)
rvargas7951bf62014-11-14 04:09:23123 if (launch_elevated) {
124 base::LaunchOptions options;
125 options.start_hidden = true;
rvargas6293e5b2014-12-01 22:53:09126 process = base::LaunchElevatedProcess(*cmd_line, options);
rvargas7951bf62014-11-14 04:09:23127 } else {
rvargas3e5d4452014-11-24 19:30:02128 process = StartSandboxedProcess(delegate, cmd_line);
rvargas7951bf62014-11-14 04:09:23129 }
130#elif defined(OS_POSIX)
131 std::string process_type =
132 cmd_line->GetSwitchValueASCII(switches::kProcessType);
133 scoped_ptr<FileDescriptorInfo> files_to_register(
134 FileDescriptorInfoImpl::Create());
135
136#if defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:24137 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
rvargas7951bf62014-11-14 04:09:23138#else
139 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
140#endif
rvargas7951bf62014-11-14 04:09:23141#endif
142
143#if defined(OS_ANDROID)
144 // Android WebView runs in single process, ensure that we never get here
145 // when running in single process mode.
146 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
147
148 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
149 *cmd_line, child_process_id, files_to_register.get());
150
151 StartChildProcess(
sievers954e37a2015-03-28 01:50:24152 cmd_line->argv(), child_process_id, files_to_register.Pass(),
153 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
154 begin_launch_time, base::Passed(&ipcfd)));
rvargas7951bf62014-11-14 04:09:23155
156#elif defined(OS_POSIX)
rvargas7951bf62014-11-14 04:09:23157 // We need to close the client end of the IPC channel to reliably detect
158 // child termination.
159
160#if !defined(OS_MACOSX)
161 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
162 *cmd_line, child_process_id, files_to_register.get());
163 if (use_zygote) {
rvargas0bf966a2015-01-10 04:16:33164 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
rvargas7951bf62014-11-14 04:09:23165 cmd_line->argv(), files_to_register.Pass(), process_type);
rvargas0bf966a2015-01-10 04:16:33166 process = base::Process(handle);
rvargas7951bf62014-11-14 04:09:23167 } else
168 // Fall through to the normal posix case below when we're not zygoting.
169#endif // !defined(OS_MACOSX)
170 {
171 // Convert FD mapping to FileHandleMappingVector
172 base::FileHandleMappingVector fds_to_map =
173 files_to_register->GetMappingWithIDAdjustment(
174 base::GlobalDescriptors::kBaseDescriptor);
175
176#if !defined(OS_MACOSX)
177 if (process_type == switches::kRendererProcess) {
178 const int sandbox_fd =
179 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
180 fds_to_map.push_back(std::make_pair(
181 sandbox_fd,
182 GetSandboxFD()));
183 }
184#endif // defined(OS_MACOSX)
185
186 // Actually launch the app.
187 base::LaunchOptions options;
188 options.environ = env;
189 options.fds_to_remap = &fds_to_map;
190
191#if defined(OS_MACOSX)
192 // Hold the MachBroker lock for the duration of LaunchProcess. The child
193 // will send its task port to the parent almost immediately after startup.
194 // The Mach message will be delivered to the parent, but updating the
195 // record of the launch will wait until after the placeholder PID is
196 // inserted below. This ensures that while the child process may send its
197 // port to the parent prior to the parent leaving LaunchProcess, the
198 // order in which the record in MachBroker is updated is correct.
199 MachBroker* broker = MachBroker::GetInstance();
200 broker->GetLock().Acquire();
201
202 // Make sure the MachBroker is running, and inform it to expect a
203 // check-in from the new process.
204 broker->EnsureRunning();
205
206 const int bootstrap_sandbox_policy = delegate->GetSandboxType();
207 if (ShouldEnableBootstrapSandbox() &&
208 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
209 options.replacement_bootstrap_name =
210 GetBootstrapSandbox()->server_bootstrap_name();
211 GetBootstrapSandbox()->PrepareToForkWithPolicy(
212 bootstrap_sandbox_policy);
213 }
214#endif // defined(OS_MACOSX)
215
rvargas0bf966a2015-01-10 04:16:33216 process = base::LaunchProcess(*cmd_line, options);
rvargas7951bf62014-11-14 04:09:23217
218#if defined(OS_MACOSX)
219 if (ShouldEnableBootstrapSandbox() &&
220 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
rvargas0bf966a2015-01-10 04:16:33221 GetBootstrapSandbox()->FinishedFork(process.Handle());
rvargas7951bf62014-11-14 04:09:23222 }
223
rvargas0bf966a2015-01-10 04:16:33224 if (process.IsValid())
rvargas960db882015-01-24 00:27:25225 broker->AddPlaceholderForPid(process.Pid(), child_process_id);
rvargas7951bf62014-11-14 04:09:23226
227 // After updating the broker, release the lock and let the child's
228 // messasge be processed on the broker's thread.
229 broker->GetLock().Release();
230#endif // defined(OS_MACOSX)
231 }
232#endif // else defined(OS_POSIX)
233#if !defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:24234 if (process.IsValid()) {
235 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
236 begin_launch_time);
237 }
238 BrowserThread::PostTask(client_thread_id, FROM_HERE,
239 base::Bind(callback,
240 use_zygote,
241 base::Passed(&process)));
rvargas7951bf62014-11-14 04:09:23242#endif // !defined(OS_ANDROID)
243}
244
sievers954e37a2015-03-28 01:50:24245void TerminateOnLauncherThread(bool zygote, base::Process process) {
246 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:23247#if defined(OS_ANDROID)
248 VLOG(1) << "ChromeProcess: Stopping process with handle "
249 << process.Handle();
250 StopChildProcess(process.Handle());
251#else
252 // Client has gone away, so just kill the process. Using exit code 0
253 // means that UMA won't treat this as a crash.
rvargaseedb7632015-03-09 23:53:45254 process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
rvargas7951bf62014-11-14 04:09:23255 // On POSIX, we must additionally reap the child.
256#if defined(OS_POSIX)
257#if !defined(OS_MACOSX)
258 if (zygote) {
259 // If the renderer was created via a zygote, we have to proxy the reaping
260 // through the zygote process.
261 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
262 } else
263#endif // !OS_MACOSX
rvargas61812772014-12-05 03:14:54264 base::EnsureProcessTerminated(process.Pass());
rvargas7951bf62014-11-14 04:09:23265#endif // OS_POSIX
266#endif // defined(OS_ANDROID)
267}
268
sievers954e37a2015-03-28 01:50:24269void SetProcessBackgroundedOnLauncherThread(base::Process process,
270 bool background) {
271 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
shrike8fbe9d32015-06-02 19:53:57272#if defined(OS_MACOSX)
273 MachBroker* broker = MachBroker::GetInstance();
274 mach_port_t task_port = broker->TaskForPid(process.Pid());
275 if (task_port != TASK_NULL) {
276 process.SetProcessBackgrounded(task_port, background);
277 }
278#else
sievers954e37a2015-03-28 01:50:24279 process.SetProcessBackgrounded(background);
shrike8fbe9d32015-06-02 19:53:57280#endif // defined(OS_MACOSX)
sievers954e37a2015-03-28 01:50:24281#if defined(OS_ANDROID)
282 SetChildProcessInForeground(process.Handle(), !background);
283#endif
284}
285
286} // anonymous namespace
[email protected]9610ef242009-11-18 02:41:26287
[email protected]fb1277e82009-11-21 20:32:30288ChildProcessLauncher::ChildProcessLauncher(
[email protected]34f48682013-03-20 00:30:18289 SandboxedProcessLauncherDelegate* delegate,
[email protected]479278702014-08-11 20:32:09290 base::CommandLine* cmd_line,
[email protected]40da3e0c2012-10-24 22:03:38291 int child_process_id,
sievers954e37a2015-03-28 01:50:24292 Client* client,
293 bool terminate_on_shutdown)
294 : client_(client),
295 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
296 exit_code_(RESULT_CODE_NORMAL_EXIT),
297 zygote_(false),
298 starting_(true),
299#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
300 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
301 defined(UNDEFINED_SANITIZER)
302 terminate_child_on_shutdown_(false),
303#else
304 terminate_child_on_shutdown_(terminate_on_shutdown),
305#endif
306 weak_factory_(this) {
307 DCHECK(CalledOnValidThread());
308 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
309 Launch(delegate, cmd_line, child_process_id);
[email protected]9610ef242009-11-18 02:41:26310}
311
312ChildProcessLauncher::~ChildProcessLauncher() {
sievers954e37a2015-03-28 01:50:24313 DCHECK(CalledOnValidThread());
314 if (process_.IsValid() && terminate_child_on_shutdown_) {
315 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
316 // don't this on the UI/IO threads.
317 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
318 base::Bind(&TerminateOnLauncherThread, zygote_,
319 base::Passed(&process_)));
320 }
321}
322
323void ChildProcessLauncher::Launch(
324 SandboxedProcessLauncherDelegate* delegate,
325 base::CommandLine* cmd_line,
326 int child_process_id) {
327 DCHECK(CalledOnValidThread());
328
329#if defined(OS_ANDROID)
330 // Android only supports renderer, sandboxed utility and gpu.
331 std::string process_type =
332 cmd_line->GetSwitchValueASCII(switches::kProcessType);
333 CHECK(process_type == switches::kGpuProcess ||
334 process_type == switches::kRendererProcess ||
335 process_type == switches::kUtilityProcess)
336 << "Unsupported process type: " << process_type;
337
338 // Non-sandboxed utility or renderer process are currently not supported.
339 DCHECK(process_type == switches::kGpuProcess ||
340 !cmd_line->HasSwitch(switches::kNoSandbox));
341
342 // We need to close the client end of the IPC channel to reliably detect
343 // child termination. We will close this fd after we create the child
344 // process which is asynchronous on Android.
345 base::ScopedFD ipcfd(delegate->TakeIpcFd().release());
346#endif
347 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
348 weak_factory_.GetWeakPtr(),
349 terminate_child_on_shutdown_));
350 BrowserThread::PostTask(
351 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
352 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
353 child_process_id, delegate,
354#if defined(OS_ANDROID)
355 base::Passed(&ipcfd),
356#endif
357 cmd_line));
358}
359
360void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
361 DCHECK(CalledOnValidThread());
362#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
363 if (zygote_) {
364 termination_status_ = ZygoteHostImpl::GetInstance()->
365 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
366 } else if (known_dead) {
367 termination_status_ =
368 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
369 } else {
370#elif defined(OS_MACOSX)
371 if (known_dead) {
372 termination_status_ =
373 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
374 } else {
375#elif defined(OS_ANDROID)
376 if (IsChildProcessOomProtected(process_.Handle())) {
377 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
378 } else {
379#else
380 {
381#endif
382 termination_status_ =
383 base::GetTerminationStatus(process_.Handle(), &exit_code_);
384 }
385}
386
387void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
388 DCHECK(CalledOnValidThread());
389 base::Process to_pass = process_.Duplicate();
390 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
391 base::Bind(&SetProcessBackgroundedOnLauncherThread,
392 base::Passed(&to_pass), background));
393}
394
395void ChildProcessLauncher::DidLaunch(
396 base::WeakPtr<ChildProcessLauncher> instance,
397 bool terminate_on_shutdown,
398 bool zygote,
399#if defined(OS_ANDROID)
400 base::ScopedFD ipcfd,
401#endif
402 base::Process process) {
403 if (!process.IsValid())
404 LOG(ERROR) << "Failed to launch child process";
405
406 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
407 // is fixed.
408 tracked_objects::ScopedTracker tracking_profile1(
409 FROM_HERE_WITH_EXPLICIT_FUNCTION(
410 "465841 ChildProcessLauncher::Context::Notify::Start"));
411
412 if (instance.get()) {
413 instance->Notify(zygote,
414#if defined(OS_ANDROID)
415 ipcfd.Pass(),
416#endif
417 process.Pass());
418 } else {
419 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
420 // is fixed.
421 tracked_objects::ScopedTracker tracking_profile4(
422 FROM_HERE_WITH_EXPLICIT_FUNCTION(
423 "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
424 if (process.IsValid() && terminate_on_shutdown) {
425 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
426 // don't this on the UI/IO threads.
427 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
428 base::Bind(&TerminateOnLauncherThread, zygote,
429 base::Passed(&process)));
430 }
431 }
432}
433
434void ChildProcessLauncher::Notify(
435 bool zygote,
436#if defined(OS_ANDROID)
437 base::ScopedFD ipcfd,
438#endif
439 base::Process process) {
440 DCHECK(CalledOnValidThread());
441 starting_ = false;
442 process_ = process.Pass();
443
444#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
445 zygote_ = zygote;
446#endif
447 if (process_.IsValid()) {
448 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
449 // is fixed.
450 tracked_objects::ScopedTracker tracking_profile2(
451 FROM_HERE_WITH_EXPLICIT_FUNCTION(
452 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
453 client_->OnProcessLaunched();
454 } else {
455 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
456 // is fixed.
457 tracked_objects::ScopedTracker tracking_profile3(
458 FROM_HERE_WITH_EXPLICIT_FUNCTION(
459 "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
460 client_->OnProcessLaunchFailed();
461 }
[email protected]9610ef242009-11-18 02:41:26462}
463
464bool ChildProcessLauncher::IsStarting() {
sievers954e37a2015-03-28 01:50:24465 // TODO(crbug.com/469248): This fails in some tests.
466 // DCHECK(CalledOnValidThread());
467 return starting_;
[email protected]9610ef242009-11-18 02:41:26468}
469
rvargas079d1842014-10-17 22:32:16470const base::Process& ChildProcessLauncher::GetProcess() const {
sievers954e37a2015-03-28 01:50:24471 // TODO(crbug.com/469248): This fails in some tests.
472 // DCHECK(CalledOnValidThread());
473 return process_;
[email protected]9610ef242009-11-18 02:41:26474}
475
[email protected]443b80e2010-12-14 00:42:23476base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
[email protected]c7691de2012-12-06 08:31:51477 bool known_dead,
[email protected]443b80e2010-12-14 00:42:23478 int* exit_code) {
sievers954e37a2015-03-28 01:50:24479 DCHECK(CalledOnValidThread());
480 if (!process_.IsValid()) {
[email protected]f3c1d3c2011-07-25 18:50:48481 // Process is already gone, so return the cached termination status.
482 if (exit_code)
sievers954e37a2015-03-28 01:50:24483 *exit_code = exit_code_;
484 return termination_status_;
[email protected]cd69619b2010-05-05 02:41:38485 }
486
sievers954e37a2015-03-28 01:50:24487 UpdateTerminationStatus(known_dead);
[email protected]f3c1d3c2011-07-25 18:50:48488 if (exit_code)
sievers954e37a2015-03-28 01:50:24489 *exit_code = exit_code_;
[email protected]f3c1d3c2011-07-25 18:50:48490
[email protected]443b80e2010-12-14 00:42:23491 // POSIX: If the process crashed, then the kernel closed the socket
492 // for it and so the child has already died by the time we get
493 // here. Since GetTerminationStatus called waitpid with WNOHANG,
494 // it'll reap the process. However, if GetTerminationStatus didn't
495 // reap the child (because it was still running), we'll need to
[email protected]cd69619b2010-05-05 02:41:38496 // Terminate via ProcessWatcher. So we can't close the handle here.
sievers954e37a2015-03-28 01:50:24497 if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
498 process_.Close();
[email protected]cd69619b2010-05-05 02:41:38499
sievers954e37a2015-03-28 01:50:24500 return termination_status_;
[email protected]358cb8e2011-05-25 02:12:45501}
[email protected]130757672012-10-24 00:26:19502
lfg06aac852015-03-23 22:36:10503ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
504 Client* client) {
sievers954e37a2015-03-28 01:50:24505 Client* ret = client_;
506 client_ = client;
507 return ret;
lfg06aac852015-03-23 22:36:10508}
509
[email protected]130757672012-10-24 00:26:19510} // namespace content