blob: c705b7db4972e4b339d5a84473f90738a63d139a [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
danakje3de838f2015-12-03 01:49:407#include <utility>
8
[email protected]037edb52011-11-15 21:14:069#include "base/bind.h"
[email protected]9610ef242009-11-18 02:41:2610#include "base/command_line.h"
thestigb7aad54f2014-09-05 18:25:3911#include "base/files/file_util.h"
agrievefd2d44ab2015-06-19 04:33:0312#include "base/i18n/icu_util.h"
[email protected]9610ef242009-11-18 02:41:2613#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1514#include "base/memory/scoped_ptr.h"
[email protected]323fdc312013-02-25 18:44:2615#include "base/metrics/histogram.h"
[email protected]dd4b51262013-07-25 21:38:2316#include "base/process/process.h"
ben03b7b9d2015-11-15 12:13:0917#include "base/strings/string_number_conversions.h"
[email protected]20305ec2011-01-21 04:55:5218#include "base/synchronization/lock.h"
[email protected]34b99632011-01-01 01:01:0619#include "base/threading/thread.h"
[email protected]87f3c082011-10-19 18:07:4420#include "content/public/browser/content_browser_client.h"
[email protected]b3aabd342012-06-04 19:33:5621#include "content/public/common/content_descriptors.h"
[email protected]c08950d22011-10-13 22:20:2922#include "content/public/common/content_switches.h"
[email protected]b39ef1cb2011-10-25 04:46:5523#include "content/public/common/result_codes.h"
[email protected]121e61382014-03-13 11:35:1524#include "content/public/common/sandboxed_process_launcher_delegate.h"
[email protected]9610ef242009-11-18 02:41:2625
26#if defined(OS_WIN)
[email protected]57999812013-02-24 05:40:5227#include "base/files/file_path.h"
[email protected]34f48682013-03-20 00:30:1828#include "content/common/sandbox_win.h"
[email protected]e25b04c92012-10-23 20:05:0629#include "content/public/common/sandbox_init.h"
[email protected]e63c4d72011-05-31 22:38:2930#elif defined(OS_MACOSX)
rsesekdba84112015-09-18 19:22:0731#include "content/browser/bootstrap_sandbox_manager_mac.h"
reveman7c45b3082015-06-04 01:27:0832#include "content/browser/browser_io_surface_manager_mac.h"
[email protected]ed0fbe62011-06-23 18:32:1133#include "content/browser/mach_broker_mac.h"
[email protected]f5bcd0f2014-06-10 14:50:4134#include "sandbox/mac/bootstrap_sandbox.h"
rsesek408d2ee52015-09-18 01:18:0435#include "sandbox/mac/pre_exec_delegate.h"
[email protected]30935362012-06-28 21:26:2336#elif defined(OS_ANDROID)
37#include "base/android/jni_android.h"
[email protected]5e44a142013-03-19 09:48:3938#include "content/browser/android/child_process_launcher_android.h"
[email protected]e63c4d72011-05-31 22:38:2939#elif defined(OS_POSIX)
[email protected]3b63f8f42011-03-28 01:54:1540#include "base/memory/singleton.h"
[email protected]a01efd22011-03-01 00:38:3241#include "content/browser/renderer_host/render_sandbox_host_linux.h"
[email protected]13d6b3c2012-07-24 01:31:3142#include "content/browser/zygote_host/zygote_host_impl_linux.h"
[email protected]a0c900e2013-09-11 18:16:1043#include "content/common/child_process_sandbox_support_impl_linux.h"
[email protected]9610ef242009-11-18 02:41:2644#endif
45
[email protected]fb1277e82009-11-21 20:32:3046#if defined(OS_POSIX)
[email protected]613eef62012-11-09 23:46:5447#include "base/posix/global_descriptors.h"
morritad95714f2014-10-01 02:37:2448#include "content/browser/file_descriptor_info_impl.h"
agrievefd2d44ab2015-06-19 04:33:0349#include "gin/v8_initializer.h"
[email protected]fb1277e82009-11-21 20:32:3050#endif
51
[email protected]130757672012-10-24 00:26:1952namespace content {
[email protected]631bb742011-11-02 11:29:3953
sievers954e37a2015-03-28 01:50:2454namespace {
[email protected]9610ef242009-11-18 02:41:2655
sievers954e37a2015-03-28 01:50:2456typedef base::Callback<void(bool,
tkentdd53cf7322015-03-23 00:54:5057#if defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:2458 base::ScopedFD,
tkentdd53cf7322015-03-23 00:54:5059#endif
sievers954e37a2015-03-28 01:50:2460 base::Process)> NotifyCallback;
tkentdd53cf7322015-03-23 00:54:5061
sievers954e37a2015-03-28 01:50:2462void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
63 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:2364 // Log the launch time, separating out the first one (which will likely be
65 // slower due to the rest of the browser initializing at the same time).
66 static bool done_first_launch = false;
67 if (done_first_launch) {
68 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
69 } else {
70 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
71 done_first_launch = true;
72 }
73}
74
sievers954e37a2015-03-28 01:50:2475#if defined(OS_ANDROID)
76// TODO(sievers): Remove this by defining better what happens on what
77// thread in the corresponding Java code.
78void OnChildProcessStartedAndroid(const NotifyCallback& callback,
79 BrowserThread::ID client_thread_id,
80 const base::TimeTicks begin_launch_time,
81 base::ScopedFD ipcfd,
82 base::ProcessHandle handle) {
83 // This can be called on the launcher thread or UI thread.
84 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
85 BrowserThread::PostTask(
86 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
87 base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
88
89 base::Closure callback_on_client_thread(
90 base::Bind(callback, false, base::Passed(&ipcfd),
91 base::Passed(base::Process(handle))));
92 if (BrowserThread::CurrentlyOn(client_thread_id)) {
93 callback_on_client_thread.Run();
94 } else {
95 BrowserThread::PostTask(
96 client_thread_id, FROM_HERE, callback_on_client_thread);
thestig774686b2015-09-15 19:34:3197 }
sievers954e37a2015-03-28 01:50:2498}
99#endif
100
101void LaunchOnLauncherThread(const NotifyCallback& callback,
102 BrowserThread::ID client_thread_id,
103 int child_process_id,
104 SandboxedProcessLauncherDelegate* delegate,
105#if defined(OS_ANDROID)
106 base::ScopedFD ipcfd,
107#endif
108 base::CommandLine* cmd_line) {
109 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:23110 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
111#if defined(OS_WIN)
sievers954e37a2015-03-28 01:50:24112 bool use_zygote = false;
rvargas7951bf62014-11-14 04:09:23113 bool launch_elevated = delegate->ShouldLaunchElevated();
rvargas7951bf62014-11-14 04:09:23114#elif defined(OS_MACOSX)
sievers954e37a2015-03-28 01:50:24115 bool use_zygote = false;
rvargas7951bf62014-11-14 04:09:23116 base::EnvironmentMap env = delegate->GetEnvironment();
117 base::ScopedFD ipcfd = delegate->TakeIpcFd();
sievers954e37a2015-03-28 01:50:24118#elif defined(OS_POSIX) && !defined(OS_ANDROID)
rvargas7951bf62014-11-14 04:09:23119 bool use_zygote = delegate->ShouldUseZygote();
120 base::EnvironmentMap env = delegate->GetEnvironment();
121 base::ScopedFD ipcfd = delegate->TakeIpcFd();
122#endif
123 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
124 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
125
rvargas3e5d4452014-11-24 19:30:02126 base::Process process;
rvargas0bf966a2015-01-10 04:16:33127#if defined(OS_WIN)
rvargas7951bf62014-11-14 04:09:23128 if (launch_elevated) {
129 base::LaunchOptions options;
130 options.start_hidden = true;
rvargas6293e5b2014-12-01 22:53:09131 process = base::LaunchElevatedProcess(*cmd_line, options);
rvargas7951bf62014-11-14 04:09:23132 } else {
rvargas3e5d4452014-11-24 19:30:02133 process = StartSandboxedProcess(delegate, cmd_line);
rvargas7951bf62014-11-14 04:09:23134 }
135#elif defined(OS_POSIX)
136 std::string process_type =
137 cmd_line->GetSwitchValueASCII(switches::kProcessType);
138 scoped_ptr<FileDescriptorInfo> files_to_register(
139 FileDescriptorInfoImpl::Create());
140
141#if defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:24142 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
rvargas7951bf62014-11-14 04:09:23143#else
danakje3de838f2015-12-03 01:49:40144 files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd));
rvargas7951bf62014-11-14 04:09:23145#endif
rvargas7951bf62014-11-14 04:09:23146#endif
147
agrievefd2d44ab2015-06-19 04:33:03148#if defined(OS_POSIX) && !defined(OS_MACOSX)
mek39ae21592015-06-16 22:30:38149 std::map<int, base::MemoryMappedFile::Region> regions;
150 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
agrieve05398f52015-06-24 18:59:00151 *cmd_line, child_process_id, files_to_register.get()
152#if defined(OS_ANDROID)
153 , &regions
154#endif
155 );
agrievefd2d44ab2015-06-19 04:33:03156#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
157 base::PlatformFile natives_pf =
158 gin::V8Initializer::GetOpenNativesFileForChildProcesses(
159 &regions[kV8NativesDataDescriptor]);
160 DCHECK_GE(natives_pf, 0);
161 files_to_register->Share(kV8NativesDataDescriptor, natives_pf);
mek39ae21592015-06-16 22:30:38162
agrievefd2d44ab2015-06-19 04:33:03163 base::MemoryMappedFile::Region snapshot_region;
164 base::PlatformFile snapshot_pf =
165 gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(
166 &snapshot_region);
167 // Failure to load the V8 snapshot is not necessarily an error. V8 can start
168 // up (slower) without the snapshot.
169 if (snapshot_pf != -1) {
170 files_to_register->Share(kV8SnapshotDataDescriptor, snapshot_pf);
171 regions.insert(std::make_pair(kV8SnapshotDataDescriptor, snapshot_region));
172 }
173
174 if (process_type != switches::kZygoteProcess) {
175 cmd_line->AppendSwitch(::switches::kV8NativesPassedByFD);
176 if (snapshot_pf != -1) {
177 cmd_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
178 }
179 }
180#endif // defined(V8_USE_EXTERNAL_STARTUP_DATA)
181#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
182
183#if defined(OS_ANDROID)
184 files_to_register->Share(
185 kAndroidICUDataDescriptor,
186 base::i18n::GetIcuDataFileHandle(&regions[kAndroidICUDataDescriptor]));
187
188 // Android WebView runs in single process, ensure that we never get here
189 // when running in single process mode.
190 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
erikcorryc94eff12015-06-08 11:29:16191
rvargas7951bf62014-11-14 04:09:23192 StartChildProcess(
danakje3de838f2015-12-03 01:49:40193 cmd_line->argv(), child_process_id, std::move(files_to_register), regions,
sievers954e37a2015-03-28 01:50:24194 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
195 begin_launch_time, base::Passed(&ipcfd)));
rvargas7951bf62014-11-14 04:09:23196
197#elif defined(OS_POSIX)
rvargas7951bf62014-11-14 04:09:23198 // We need to close the client end of the IPC channel to reliably detect
199 // child termination.
200
201#if !defined(OS_MACOSX)
rvargas7951bf62014-11-14 04:09:23202 if (use_zygote) {
rvargas0bf966a2015-01-10 04:16:33203 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
danakje3de838f2015-12-03 01:49:40204 cmd_line->argv(), std::move(files_to_register), process_type);
rvargas0bf966a2015-01-10 04:16:33205 process = base::Process(handle);
rvargas7951bf62014-11-14 04:09:23206 } else
207 // Fall through to the normal posix case below when we're not zygoting.
208#endif // !defined(OS_MACOSX)
209 {
210 // Convert FD mapping to FileHandleMappingVector
211 base::FileHandleMappingVector fds_to_map =
212 files_to_register->GetMappingWithIDAdjustment(
213 base::GlobalDescriptors::kBaseDescriptor);
214
215#if !defined(OS_MACOSX)
216 if (process_type == switches::kRendererProcess) {
217 const int sandbox_fd =
218 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
219 fds_to_map.push_back(std::make_pair(
220 sandbox_fd,
221 GetSandboxFD()));
222 }
223#endif // defined(OS_MACOSX)
224
225 // Actually launch the app.
226 base::LaunchOptions options;
227 options.environ = env;
228 options.fds_to_remap = &fds_to_map;
229
230#if defined(OS_MACOSX)
231 // Hold the MachBroker lock for the duration of LaunchProcess. The child
232 // will send its task port to the parent almost immediately after startup.
233 // The Mach message will be delivered to the parent, but updating the
234 // record of the launch will wait until after the placeholder PID is
235 // inserted below. This ensures that while the child process may send its
236 // port to the parent prior to the parent leaving LaunchProcess, the
237 // order in which the record in MachBroker is updated is correct.
238 MachBroker* broker = MachBroker::GetInstance();
239 broker->GetLock().Acquire();
240
241 // Make sure the MachBroker is running, and inform it to expect a
242 // check-in from the new process.
243 broker->EnsureRunning();
244
reveman7c45b3082015-06-04 01:27:08245 // Make sure the IOSurfaceManager service is running.
246 BrowserIOSurfaceManager::GetInstance()->EnsureRunning();
247
rsesekdba84112015-09-18 19:22:07248 const SandboxType sandbox_type = delegate->GetSandboxType();
rsesek408d2ee52015-09-18 01:18:04249 scoped_ptr<sandbox::PreExecDelegate> pre_exec_delegate;
rsesekdba84112015-09-18 19:22:07250 if (BootstrapSandboxManager::ShouldEnable()) {
251 BootstrapSandboxManager* sandbox_manager =
252 BootstrapSandboxManager::GetInstance();
253 if (sandbox_manager->EnabledForSandbox(sandbox_type)) {
254 pre_exec_delegate =
255 sandbox_manager->sandbox()->NewClient(sandbox_type).Pass();
256 }
rvargas7951bf62014-11-14 04:09:23257 }
rsesek408d2ee52015-09-18 01:18:04258 options.pre_exec_delegate = pre_exec_delegate.get();
rvargas7951bf62014-11-14 04:09:23259#endif // defined(OS_MACOSX)
260
rvargas0bf966a2015-01-10 04:16:33261 process = base::LaunchProcess(*cmd_line, options);
rvargas7951bf62014-11-14 04:09:23262
263#if defined(OS_MACOSX)
rsesek408d2ee52015-09-18 01:18:04264 if (process.IsValid()) {
rvargas960db882015-01-24 00:27:25265 broker->AddPlaceholderForPid(process.Pid(), child_process_id);
rsesek408d2ee52015-09-18 01:18:04266 } else {
267 if (pre_exec_delegate) {
rsesekdba84112015-09-18 19:22:07268 BootstrapSandboxManager::GetInstance()->sandbox()->RevokeToken(
rsesek408d2ee52015-09-18 01:18:04269 pre_exec_delegate->sandbox_token());
270 }
271 }
rvargas7951bf62014-11-14 04:09:23272
273 // After updating the broker, release the lock and let the child's
274 // messasge be processed on the broker's thread.
275 broker->GetLock().Release();
276#endif // defined(OS_MACOSX)
277 }
278#endif // else defined(OS_POSIX)
279#if !defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:24280 if (process.IsValid()) {
281 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
282 begin_launch_time);
283 }
284 BrowserThread::PostTask(client_thread_id, FROM_HERE,
285 base::Bind(callback,
286 use_zygote,
287 base::Passed(&process)));
rvargas7951bf62014-11-14 04:09:23288#endif // !defined(OS_ANDROID)
289}
290
sievers954e37a2015-03-28 01:50:24291void TerminateOnLauncherThread(bool zygote, base::Process process) {
292 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:23293#if defined(OS_ANDROID)
294 VLOG(1) << "ChromeProcess: Stopping process with handle "
295 << process.Handle();
296 StopChildProcess(process.Handle());
297#else
298 // Client has gone away, so just kill the process. Using exit code 0
299 // means that UMA won't treat this as a crash.
rvargaseedb7632015-03-09 23:53:45300 process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
rvargas7951bf62014-11-14 04:09:23301 // On POSIX, we must additionally reap the child.
302#if defined(OS_POSIX)
303#if !defined(OS_MACOSX)
304 if (zygote) {
305 // If the renderer was created via a zygote, we have to proxy the reaping
306 // through the zygote process.
307 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
308 } else
309#endif // !OS_MACOSX
danakje3de838f2015-12-03 01:49:40310 base::EnsureProcessTerminated(std::move(process));
rvargas7951bf62014-11-14 04:09:23311#endif // OS_POSIX
312#endif // defined(OS_ANDROID)
313}
314
sievers954e37a2015-03-28 01:50:24315void SetProcessBackgroundedOnLauncherThread(base::Process process,
316 bool background) {
317 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
shrike77144012015-10-02 02:46:58318 if (process.CanBackgroundProcesses()) {
319 process.SetProcessBackgrounded(background);
320 }
sievers954e37a2015-03-28 01:50:24321#if defined(OS_ANDROID)
322 SetChildProcessInForeground(process.Handle(), !background);
323#endif
324}
325
ben03b7b9d2015-11-15 12:13:09326} // namespace
[email protected]9610ef242009-11-18 02:41:26327
[email protected]fb1277e82009-11-21 20:32:30328ChildProcessLauncher::ChildProcessLauncher(
[email protected]34f48682013-03-20 00:30:18329 SandboxedProcessLauncherDelegate* delegate,
[email protected]479278702014-08-11 20:32:09330 base::CommandLine* cmd_line,
[email protected]40da3e0c2012-10-24 22:03:38331 int child_process_id,
sievers954e37a2015-03-28 01:50:24332 Client* client,
333 bool terminate_on_shutdown)
334 : client_(client),
335 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
336 exit_code_(RESULT_CODE_NORMAL_EXIT),
337 zygote_(false),
338 starting_(true),
339#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
340 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
341 defined(UNDEFINED_SANITIZER)
342 terminate_child_on_shutdown_(false),
343#else
344 terminate_child_on_shutdown_(terminate_on_shutdown),
345#endif
346 weak_factory_(this) {
347 DCHECK(CalledOnValidThread());
348 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
349 Launch(delegate, cmd_line, child_process_id);
[email protected]9610ef242009-11-18 02:41:26350}
351
352ChildProcessLauncher::~ChildProcessLauncher() {
sievers954e37a2015-03-28 01:50:24353 DCHECK(CalledOnValidThread());
354 if (process_.IsValid() && terminate_child_on_shutdown_) {
355 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
356 // don't this on the UI/IO threads.
357 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
358 base::Bind(&TerminateOnLauncherThread, zygote_,
359 base::Passed(&process_)));
360 }
361}
362
363void ChildProcessLauncher::Launch(
364 SandboxedProcessLauncherDelegate* delegate,
365 base::CommandLine* cmd_line,
366 int child_process_id) {
367 DCHECK(CalledOnValidThread());
368
369#if defined(OS_ANDROID)
370 // Android only supports renderer, sandboxed utility and gpu.
371 std::string process_type =
372 cmd_line->GetSwitchValueASCII(switches::kProcessType);
373 CHECK(process_type == switches::kGpuProcess ||
374 process_type == switches::kRendererProcess ||
hshi11e97112015-08-29 00:14:36375#if defined(ENABLE_PLUGINS)
376 process_type == switches::kPpapiPluginProcess ||
377#endif
sievers954e37a2015-03-28 01:50:24378 process_type == switches::kUtilityProcess)
379 << "Unsupported process type: " << process_type;
380
381 // Non-sandboxed utility or renderer process are currently not supported.
382 DCHECK(process_type == switches::kGpuProcess ||
383 !cmd_line->HasSwitch(switches::kNoSandbox));
384
385 // We need to close the client end of the IPC channel to reliably detect
386 // child termination. We will close this fd after we create the child
387 // process which is asynchronous on Android.
388 base::ScopedFD ipcfd(delegate->TakeIpcFd().release());
389#endif
390 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
391 weak_factory_.GetWeakPtr(),
392 terminate_child_on_shutdown_));
393 BrowserThread::PostTask(
394 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
395 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
396 child_process_id, delegate,
397#if defined(OS_ANDROID)
398 base::Passed(&ipcfd),
399#endif
400 cmd_line));
401}
402
403void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
404 DCHECK(CalledOnValidThread());
405#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
406 if (zygote_) {
407 termination_status_ = ZygoteHostImpl::GetInstance()->
408 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
409 } else if (known_dead) {
410 termination_status_ =
411 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
412 } else {
413#elif defined(OS_MACOSX)
414 if (known_dead) {
415 termination_status_ =
416 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
417 } else {
418#elif defined(OS_ANDROID)
419 if (IsChildProcessOomProtected(process_.Handle())) {
420 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
421 } else {
422#else
423 {
424#endif
425 termination_status_ =
426 base::GetTerminationStatus(process_.Handle(), &exit_code_);
427 }
428}
429
430void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
431 DCHECK(CalledOnValidThread());
432 base::Process to_pass = process_.Duplicate();
433 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
434 base::Bind(&SetProcessBackgroundedOnLauncherThread,
435 base::Passed(&to_pass), background));
436}
437
438void ChildProcessLauncher::DidLaunch(
439 base::WeakPtr<ChildProcessLauncher> instance,
440 bool terminate_on_shutdown,
441 bool zygote,
442#if defined(OS_ANDROID)
443 base::ScopedFD ipcfd,
444#endif
445 base::Process process) {
446 if (!process.IsValid())
447 LOG(ERROR) << "Failed to launch child process";
448
sievers954e37a2015-03-28 01:50:24449 if (instance.get()) {
450 instance->Notify(zygote,
451#if defined(OS_ANDROID)
danakje3de838f2015-12-03 01:49:40452 std::move(ipcfd),
sievers954e37a2015-03-28 01:50:24453#endif
danakje3de838f2015-12-03 01:49:40454 std::move(process));
sievers954e37a2015-03-28 01:50:24455 } else {
sievers954e37a2015-03-28 01:50:24456 if (process.IsValid() && terminate_on_shutdown) {
457 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
458 // don't this on the UI/IO threads.
459 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
460 base::Bind(&TerminateOnLauncherThread, zygote,
461 base::Passed(&process)));
462 }
463 }
464}
465
466void ChildProcessLauncher::Notify(
467 bool zygote,
468#if defined(OS_ANDROID)
469 base::ScopedFD ipcfd,
470#endif
471 base::Process process) {
472 DCHECK(CalledOnValidThread());
473 starting_ = false;
danakje3de838f2015-12-03 01:49:40474 process_ = std::move(process);
sievers954e37a2015-03-28 01:50:24475
476#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
477 zygote_ = zygote;
478#endif
479 if (process_.IsValid()) {
sievers954e37a2015-03-28 01:50:24480 client_->OnProcessLaunched();
481 } else {
wfh0d9532a2015-09-02 23:18:58482 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED;
sievers954e37a2015-03-28 01:50:24483 client_->OnProcessLaunchFailed();
484 }
[email protected]9610ef242009-11-18 02:41:26485}
486
[email protected]9610ef242009-11-18 02:41:26487bool ChildProcessLauncher::IsStarting() {
sievers954e37a2015-03-28 01:50:24488 // TODO(crbug.com/469248): This fails in some tests.
489 // DCHECK(CalledOnValidThread());
490 return starting_;
[email protected]9610ef242009-11-18 02:41:26491}
492
rvargas079d1842014-10-17 22:32:16493const base::Process& ChildProcessLauncher::GetProcess() const {
sievers954e37a2015-03-28 01:50:24494 // TODO(crbug.com/469248): This fails in some tests.
495 // DCHECK(CalledOnValidThread());
496 return process_;
[email protected]9610ef242009-11-18 02:41:26497}
498
[email protected]443b80e2010-12-14 00:42:23499base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
[email protected]c7691de2012-12-06 08:31:51500 bool known_dead,
[email protected]443b80e2010-12-14 00:42:23501 int* exit_code) {
sievers954e37a2015-03-28 01:50:24502 DCHECK(CalledOnValidThread());
503 if (!process_.IsValid()) {
[email protected]f3c1d3c2011-07-25 18:50:48504 // Process is already gone, so return the cached termination status.
505 if (exit_code)
sievers954e37a2015-03-28 01:50:24506 *exit_code = exit_code_;
507 return termination_status_;
[email protected]cd69619b2010-05-05 02:41:38508 }
509
sievers954e37a2015-03-28 01:50:24510 UpdateTerminationStatus(known_dead);
[email protected]f3c1d3c2011-07-25 18:50:48511 if (exit_code)
sievers954e37a2015-03-28 01:50:24512 *exit_code = exit_code_;
[email protected]f3c1d3c2011-07-25 18:50:48513
[email protected]443b80e2010-12-14 00:42:23514 // POSIX: If the process crashed, then the kernel closed the socket
515 // for it and so the child has already died by the time we get
516 // here. Since GetTerminationStatus called waitpid with WNOHANG,
517 // it'll reap the process. However, if GetTerminationStatus didn't
518 // reap the child (because it was still running), we'll need to
[email protected]cd69619b2010-05-05 02:41:38519 // Terminate via ProcessWatcher. So we can't close the handle here.
sievers954e37a2015-03-28 01:50:24520 if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
521 process_.Close();
[email protected]cd69619b2010-05-05 02:41:38522
sievers954e37a2015-03-28 01:50:24523 return termination_status_;
[email protected]358cb8e2011-05-25 02:12:45524}
[email protected]130757672012-10-24 00:26:19525
lfg06aac852015-03-23 22:36:10526ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
527 Client* client) {
sievers954e37a2015-03-28 01:50:24528 Client* ret = client_;
529 client_ = client;
530 return ret;
lfg06aac852015-03-23 22:36:10531}
532
[email protected]130757672012-10-24 00:26:19533} // namespace content