blob: 991223de69ec80e42d2b86be789c16320a173f5e [file] [log] [blame]
[email protected]ffb69732012-02-08 17:33:231// Copyright (c) 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]eb1bd832010-05-18 20:39:587#include <utility> // For std::pair.
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"
[email protected]2ce26c432011-09-19 17:08:1211#include "base/file_util.h"
[email protected]9610ef242009-11-18 02:41:2612#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1513#include "base/memory/scoped_ptr.h"
[email protected]323fdc312013-02-25 18:44:2614#include "base/metrics/histogram.h"
[email protected]eaac71592011-11-23 18:32:0015#include "base/process_util.h"
[email protected]20305ec2011-01-21 04:55:5216#include "base/synchronization/lock.h"
[email protected]34b99632011-01-01 01:01:0617#include "base/threading/thread.h"
[email protected]c38831a12011-10-28 12:44:4918#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4419#include "content/public/browser/content_browser_client.h"
[email protected]b3aabd342012-06-04 19:33:5620#include "content/public/common/content_descriptors.h"
[email protected]c08950d22011-10-13 22:20:2921#include "content/public/common/content_switches.h"
[email protected]b39ef1cb2011-10-25 04:46:5522#include "content/public/common/result_codes.h"
[email protected]9610ef242009-11-18 02:41:2623
24#if defined(OS_WIN)
[email protected]57999812013-02-24 05:40:5225#include "base/files/file_path.h"
[email protected]cd5fa1a2011-05-28 18:21:4726#include "content/common/sandbox_policy.h"
[email protected]e25b04c92012-10-23 20:05:0627#include "content/public/common/sandbox_init.h"
[email protected]e63c4d72011-05-31 22:38:2928#elif defined(OS_MACOSX)
[email protected]ed0fbe62011-06-23 18:32:1129#include "content/browser/mach_broker_mac.h"
[email protected]30935362012-06-28 21:26:2330#elif defined(OS_ANDROID)
31#include "base/android/jni_android.h"
[email protected]5e44a142013-03-19 09:48:3932#include "content/browser/android/child_process_launcher_android.h"
[email protected]e63c4d72011-05-31 22:38:2933#elif defined(OS_POSIX)
[email protected]3b63f8f42011-03-28 01:54:1534#include "base/memory/singleton.h"
[email protected]a01efd22011-03-01 00:38:3235#include "content/browser/renderer_host/render_sandbox_host_linux.h"
[email protected]13d6b3c2012-07-24 01:31:3136#include "content/browser/zygote_host/zygote_host_impl_linux.h"
[email protected]9610ef242009-11-18 02:41:2637#endif
38
[email protected]fb1277e82009-11-21 20:32:3039#if defined(OS_POSIX)
[email protected]613eef62012-11-09 23:46:5440#include "base/posix/global_descriptors.h"
[email protected]fb1277e82009-11-21 20:32:3041#endif
42
[email protected]130757672012-10-24 00:26:1943namespace content {
[email protected]631bb742011-11-02 11:29:3944
[email protected]9610ef242009-11-18 02:41:2645// Having the functionality of ChildProcessLauncher be in an internal
46// ref counted object allows us to automatically terminate the process when the
47// parent class destructs, while still holding on to state that we need.
48class ChildProcessLauncher::Context
49 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
50 public:
[email protected]fb1277e82009-11-21 20:32:3051 Context()
[email protected]18cbea32010-10-13 19:56:0052 : client_(NULL),
53 client_thread_id_(BrowserThread::UI),
[email protected]f3c1d3c2011-07-25 18:50:4854 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
[email protected]130757672012-10-24 00:26:1955 exit_code_(RESULT_CODE_NORMAL_EXIT),
[email protected]08c426a2012-04-10 20:37:3356 starting_(true)
[email protected]ffb69732012-02-08 17:33:2357#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]fb1277e82009-11-21 20:32:3058 , zygote_(false)
59#endif
60 {
[email protected]08c426a2012-04-10 20:37:3361#if defined(OS_POSIX)
62 terminate_child_on_shutdown_ = !CommandLine::ForCurrentProcess()->
[email protected]719a2052012-07-30 21:00:4363 HasSwitch(switches::kChildCleanExit);
[email protected]08c426a2012-04-10 20:37:3364#else
65 terminate_child_on_shutdown_ = true;
66#endif
[email protected]fb1277e82009-11-21 20:32:3067 }
[email protected]9610ef242009-11-18 02:41:2668
[email protected]fb1277e82009-11-21 20:32:3069 void Launch(
70#if defined(OS_WIN)
[email protected]2dec8ec2013-02-07 19:20:3471 const base::FilePath& exposed_dir,
[email protected]30935362012-06-28 21:26:2372#elif defined(OS_ANDROID)
73 int ipcfd,
[email protected]fb1277e82009-11-21 20:32:3074#elif defined(OS_POSIX)
[email protected]7c4ea142010-01-26 05:15:4275 bool use_zygote,
[email protected]a82af392012-02-24 04:40:2076 const base::EnvironmentVector& environ,
[email protected]fb1277e82009-11-21 20:32:3077 int ipcfd,
78#endif
79 CommandLine* cmd_line,
[email protected]40da3e0c2012-10-24 22:03:3880 int child_process_id,
[email protected]fb1277e82009-11-21 20:32:3081 Client* client) {
[email protected]9610ef242009-11-18 02:41:2682 client_ = client;
83
[email protected]d04e7662010-10-10 22:24:4884 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
[email protected]9610ef242009-11-18 02:41:2685
[email protected]30935362012-06-28 21:26:2386#if defined(OS_ANDROID)
87 // We need to close the client end of the IPC channel to reliably detect
88 // child termination. We will close this fd after we create the child
89 // process which is asynchronous on Android.
90 ipcfd_ = ipcfd;
91#endif
[email protected]d04e7662010-10-10 22:24:4892 BrowserThread::PostTask(
93 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
[email protected]037edb52011-11-15 21:14:0694 base::Bind(
[email protected]fb1277e82009-11-21 20:32:3095 &Context::LaunchInternal,
[email protected]e2024782011-09-07 20:20:5196 make_scoped_refptr(this),
97 client_thread_id_,
[email protected]40da3e0c2012-10-24 22:03:3898 child_process_id,
[email protected]fb1277e82009-11-21 20:32:3099#if defined(OS_WIN)
100 exposed_dir,
[email protected]30935362012-06-28 21:26:23101#elif defined(OS_ANDROID)
102 ipcfd,
[email protected]eb1bd832010-05-18 20:39:58103#elif defined(OS_POSIX)
[email protected]7c4ea142010-01-26 05:15:42104 use_zygote,
[email protected]3d2217d2009-11-23 21:26:47105 environ,
[email protected]fb1277e82009-11-21 20:32:30106 ipcfd,
107#endif
108 cmd_line));
[email protected]9610ef242009-11-18 02:41:26109 }
110
[email protected]30935362012-06-28 21:26:23111#if defined(OS_ANDROID)
[email protected]cee179e2013-03-19 01:43:36112 static void OnChildProcessStarted(
[email protected]30935362012-06-28 21:26:23113 // |this_object| is NOT thread safe. Only use it to post a task back.
114 scoped_refptr<Context> this_object,
115 BrowserThread::ID client_thread_id,
[email protected]323fdc312013-02-25 18:44:26116 const base::TimeTicks begin_launch_time,
[email protected]30935362012-06-28 21:26:23117 base::ProcessHandle handle) {
[email protected]323fdc312013-02-25 18:44:26118 RecordHistograms(begin_launch_time);
[email protected]30935362012-06-28 21:26:23119 if (BrowserThread::CurrentlyOn(client_thread_id)) {
120 // This is always invoked on the UI thread which is commonly the
121 // |client_thread_id| so we can shortcut one PostTask.
122 this_object->Notify(handle);
123 } else {
124 BrowserThread::PostTask(
125 client_thread_id, FROM_HERE,
126 base::Bind(
127 &ChildProcessLauncher::Context::Notify,
128 this_object,
129 handle));
130 }
131 }
132#endif
133
[email protected]9610ef242009-11-18 02:41:26134 void ResetClient() {
135 // No need for locking as this function gets called on the same thread that
136 // client_ would be used.
[email protected]d04e7662010-10-10 22:24:48137 CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
[email protected]9610ef242009-11-18 02:41:26138 client_ = NULL;
139 }
140
[email protected]358cb8e2011-05-25 02:12:45141 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
142 terminate_child_on_shutdown_ = terminate_on_shutdown;
143 }
144
[email protected]9610ef242009-11-18 02:41:26145 private:
146 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
147 friend class ChildProcessLauncher;
148
149 ~Context() {
150 Terminate();
151 }
152
[email protected]323fdc312013-02-25 18:44:26153 static void RecordHistograms(const base::TimeTicks begin_launch_time) {
154 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
155 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
156 RecordLaunchHistograms(launch_time);
157 } else {
158 BrowserThread::PostTask(
159 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
160 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
161 launch_time));
162 }
163 }
164
165 static void RecordLaunchHistograms(const base::TimeDelta launch_time) {
166 // Log the launch time, separating out the first one (which will likely be
167 // slower due to the rest of the browser initializing at the same time).
168 static bool done_first_launch = false;
169 if (done_first_launch) {
170 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
171 } else {
172 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
173 done_first_launch = true;
174 }
175 }
176
[email protected]e2024782011-09-07 20:20:51177 static void LaunchInternal(
178 // |this_object| is NOT thread safe. Only use it to post a task back.
179 scoped_refptr<Context> this_object,
180 BrowserThread::ID client_thread_id,
[email protected]40da3e0c2012-10-24 22:03:38181 int child_process_id,
[email protected]fb1277e82009-11-21 20:32:30182#if defined(OS_WIN)
[email protected]2dec8ec2013-02-07 19:20:34183 const base::FilePath& exposed_dir,
[email protected]30935362012-06-28 21:26:23184#elif defined(OS_ANDROID)
185 int ipcfd,
[email protected]fb1277e82009-11-21 20:32:30186#elif defined(OS_POSIX)
[email protected]7c4ea142010-01-26 05:15:42187 bool use_zygote,
[email protected]a82af392012-02-24 04:40:20188 const base::EnvironmentVector& env,
[email protected]fb1277e82009-11-21 20:32:30189 int ipcfd,
190#endif
191 CommandLine* cmd_line) {
[email protected]9610ef242009-11-18 02:41:26192 scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
[email protected]323fdc312013-02-25 18:44:26193 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
[email protected]2ce26c432011-09-19 17:08:12194
[email protected]9610ef242009-11-18 02:41:26195#if defined(OS_WIN)
[email protected]dcc72db2013-01-02 00:44:18196 base::ProcessHandle handle = StartProcessWithAccess(cmd_line, exposed_dir);
[email protected]30935362012-06-28 21:26:23197#elif defined(OS_ANDROID)
[email protected]8b02bf172013-01-12 17:05:26198 // Android WebView runs in single process, ensure that we never get here
199 // when running in single process mode.
200 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
201
[email protected]30935362012-06-28 21:26:23202 std::string process_type =
203 cmd_line->GetSwitchValueASCII(switches::kProcessType);
[email protected]130757672012-10-24 00:26:19204 std::vector<FileDescriptorInfo> files_to_register;
[email protected]c7abd422012-09-25 00:20:08205 files_to_register.push_back(
[email protected]130757672012-10-24 00:26:19206 FileDescriptorInfo(kPrimaryIPCChannel,
[email protected]c7abd422012-09-25 00:20:08207 base::FileDescriptor(ipcfd, false)));
208
[email protected]130757672012-10-24 00:26:19209 GetContentClient()->browser()->
[email protected]40da3e0c2012-10-24 22:03:38210 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
211 &files_to_register);
[email protected]30935362012-06-28 21:26:23212
[email protected]cee179e2013-03-19 01:43:36213 StartChildProcess(cmd_line->argv(), files_to_register,
214 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
[email protected]323fdc312013-02-25 18:44:26215 this_object, client_thread_id, begin_launch_time));
[email protected]30935362012-06-28 21:26:23216
[email protected]9610ef242009-11-18 02:41:26217#elif defined(OS_POSIX)
[email protected]30935362012-06-28 21:26:23218 base::ProcessHandle handle = base::kNullProcessHandle;
[email protected]c7abd422012-09-25 00:20:08219 // We need to close the client end of the IPC channel to reliably detect
220 // child termination.
[email protected]2ce26c432011-09-19 17:08:12221 file_util::ScopedFD ipcfd_closer(&ipcfd);
[email protected]9610ef242009-11-18 02:41:26222
[email protected]54457f32011-04-15 22:05:29223 std::string process_type =
224 cmd_line->GetSwitchValueASCII(switches::kProcessType);
[email protected]130757672012-10-24 00:26:19225 std::vector<FileDescriptorInfo> files_to_register;
[email protected]c7abd422012-09-25 00:20:08226 files_to_register.push_back(
[email protected]130757672012-10-24 00:26:19227 FileDescriptorInfo(kPrimaryIPCChannel,
[email protected]c7abd422012-09-25 00:20:08228 base::FileDescriptor(ipcfd, false)));
229
[email protected]30935362012-06-28 21:26:23230#if !defined(OS_MACOSX)
[email protected]130757672012-10-24 00:26:19231 GetContentClient()->browser()->
[email protected]40da3e0c2012-10-24 22:03:38232 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
233 &files_to_register);
[email protected]7c4ea142010-01-26 05:15:42234 if (use_zygote) {
[email protected]c2c68b1f2012-02-25 00:29:15235 handle = ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line->argv(),
[email protected]a1733df2012-06-22 11:24:18236 files_to_register,
[email protected]c2c68b1f2012-02-25 00:29:15237 process_type);
[email protected]7c4ea142010-01-26 05:15:42238 } else
239 // Fall through to the normal posix case below when we're not zygoting.
[email protected]30935362012-06-28 21:26:23240#endif // !defined(OS_MACOSX)
[email protected]fb1277e82009-11-21 20:32:30241 {
[email protected]a1733df2012-06-22 11:24:18242 // Convert FD mapping to FileHandleMappingVector
[email protected]a82af392012-02-24 04:40:20243 base::FileHandleMappingVector fds_to_map;
[email protected]40da3e0c2012-10-24 22:03:38244 for (size_t i = 0; i < files_to_register.size(); ++i) {
[email protected]54457f32011-04-15 22:05:29245 fds_to_map.push_back(std::make_pair(
[email protected]40da3e0c2012-10-24 22:03:38246 files_to_register[i].fd.fd,
247 files_to_register[i].id +
248 base::GlobalDescriptors::kBaseDescriptor));
[email protected]9610ef242009-11-18 02:41:26249 }
[email protected]a1733df2012-06-22 11:24:18250
[email protected]30935362012-06-28 21:26:23251#if !defined(OS_MACOSX)
[email protected]b80f68432011-05-02 17:22:30252 if (process_type == switches::kRendererProcess) {
[email protected]fb1277e82009-11-21 20:32:30253 const int sandbox_fd =
[email protected]d3c6c0d72010-12-09 08:15:04254 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
[email protected]fb1277e82009-11-21 20:32:30255 fds_to_map.push_back(std::make_pair(
256 sandbox_fd,
257 kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
258 }
[email protected]30935362012-06-28 21:26:23259#endif // defined(OS_MACOSX)
[email protected]9610ef242009-11-18 02:41:26260
[email protected]84b2d1d2011-09-01 21:44:24261 // Actually launch the app.
262 base::LaunchOptions options;
263 options.environ = &env;
264 options.fds_to_remap = &fds_to_map;
265
[email protected]c0028792010-01-12 00:39:15266#if defined(OS_MACOSX)
[email protected]84b2d1d2011-09-01 21:44:24267 // Use synchronization to make sure that the MachBroker is ready to
268 // receive a check-in from the new process before the new process
269 // actually tries to check in.
270 base::LaunchSynchronizationHandle synchronization_handle;
271 options.synchronize = &synchronization_handle;
272#endif // defined(OS_MACOSX)
273
274 bool launched = base::LaunchProcess(*cmd_line, options, &handle);
275
276#if defined(OS_MACOSX)
277 if (launched) {
[email protected]dc8caba2010-12-13 16:52:35278 MachBroker* broker = MachBroker::GetInstance();
[email protected]84b2d1d2011-09-01 21:44:24279 {
280 base::AutoLock lock(broker->GetLock());
[email protected]b88a7492010-09-17 12:28:32281
[email protected]84b2d1d2011-09-01 21:44:24282 // Make sure the MachBroker is running, and inform it to expect a
283 // check-in from the new process.
284 broker->EnsureRunning();
[email protected]b88a7492010-09-17 12:28:32285 broker->AddPlaceholderForPid(handle);
[email protected]84b2d1d2011-09-01 21:44:24286 }
287
288 // Now that the MachBroker is ready, the child may continue.
289 base::LaunchSynchronize(synchronization_handle);
290 }
291#endif // defined(OS_MACOSX)
292
[email protected]c0028792010-01-12 00:39:15293 if (!launched)
[email protected]9610ef242009-11-18 02:41:26294 handle = base::kNullProcessHandle;
295 }
[email protected]c0028792010-01-12 00:39:15296#endif // else defined(OS_POSIX)
[email protected]30935362012-06-28 21:26:23297#if !defined(OS_ANDROID)
[email protected]323fdc312013-02-25 18:44:26298 if (handle)
299 RecordHistograms(begin_launch_time);
[email protected]30935362012-06-28 21:26:23300 BrowserThread::PostTask(
301 client_thread_id, FROM_HERE,
302 base::Bind(
303 &Context::Notify,
304 this_object.get(),
305#if defined(OS_POSIX) && !defined(OS_MACOSX)
306 use_zygote,
[email protected]fb1277e82009-11-21 20:32:30307#endif
[email protected]30935362012-06-28 21:26:23308 handle));
309#endif // !defined(OS_ANDROID)
[email protected]9610ef242009-11-18 02:41:26310 }
311
[email protected]cd69619b2010-05-05 02:41:38312 void Notify(
[email protected]ffb69732012-02-08 17:33:23313#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]fb1277e82009-11-21 20:32:30314 bool zygote,
315#endif
316 base::ProcessHandle handle) {
[email protected]30935362012-06-28 21:26:23317#if defined(OS_ANDROID)
318 // Finally close the ipcfd
319 file_util::ScopedFD ipcfd_closer(&ipcfd_);
320#endif
[email protected]9610ef242009-11-18 02:41:26321 starting_ = false;
322 process_.set_handle(handle);
[email protected]e51ddf252011-10-12 17:33:21323 if (!handle)
324 LOG(ERROR) << "Failed to launch child process";
325
[email protected]ffb69732012-02-08 17:33:23326#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]9610ef242009-11-18 02:41:26327 zygote_ = zygote;
[email protected]fb1277e82009-11-21 20:32:30328#endif
[email protected]9610ef242009-11-18 02:41:26329 if (client_) {
330 client_->OnProcessLaunched();
331 } else {
332 Terminate();
333 }
334 }
335
336 void Terminate() {
337 if (!process_.handle())
338 return;
339
[email protected]358cb8e2011-05-25 02:12:45340 if (!terminate_child_on_shutdown_)
341 return;
342
[email protected]9610ef242009-11-18 02:41:26343 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
344 // don't this on the UI/IO threads.
[email protected]d04e7662010-10-10 22:24:48345 BrowserThread::PostTask(
346 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
[email protected]037edb52011-11-15 21:14:06347 base::Bind(
[email protected]e2024782011-09-07 20:20:51348 &Context::TerminateInternal,
[email protected]ffb69732012-02-08 17:33:23349#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]fb1277e82009-11-21 20:32:30350 zygote_,
351#endif
352 process_.handle()));
[email protected]9610ef242009-11-18 02:41:26353 process_.set_handle(base::kNullProcessHandle);
354 }
355
[email protected]e2024782011-09-07 20:20:51356 static void SetProcessBackgrounded(base::ProcessHandle handle,
357 bool background) {
358 base::Process process(handle);
359 process.SetProcessBackgrounded(background);
[email protected]3e55e212011-03-24 19:45:02360 }
361
[email protected]fb1277e82009-11-21 20:32:30362 static void TerminateInternal(
[email protected]ffb69732012-02-08 17:33:23363#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]fb1277e82009-11-21 20:32:30364 bool zygote,
365#endif
366 base::ProcessHandle handle) {
[email protected]30935362012-06-28 21:26:23367#if defined(OS_ANDROID)
368 LOG(INFO) << "ChromeProcess: Stopping process with handle " << handle;
[email protected]cee179e2013-03-19 01:43:36369 StopChildProcess(handle);
[email protected]30935362012-06-28 21:26:23370#else
[email protected]9610ef242009-11-18 02:41:26371 base::Process process(handle);
372 // Client has gone away, so just kill the process. Using exit code 0
373 // means that UMA won't treat this as a crash.
[email protected]130757672012-10-24 00:26:19374 process.Terminate(RESULT_CODE_NORMAL_EXIT);
[email protected]9610ef242009-11-18 02:41:26375 // On POSIX, we must additionally reap the child.
376#if defined(OS_POSIX)
[email protected]30935362012-06-28 21:26:23377#if !defined(OS_MACOSX)
[email protected]fb1277e82009-11-21 20:32:30378 if (zygote) {
[email protected]9610ef242009-11-18 02:41:26379 // If the renderer was created via a zygote, we have to proxy the reaping
380 // through the zygote process.
[email protected]c2c68b1f2012-02-25 00:29:15381 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle);
[email protected]fb1277e82009-11-21 20:32:30382 } else
[email protected]e63c4d72011-05-31 22:38:29383#endif // !OS_MACOSX
[email protected]fb1277e82009-11-21 20:32:30384 {
[email protected]eaac71592011-11-23 18:32:00385 base::EnsureProcessTerminated(handle);
[email protected]9610ef242009-11-18 02:41:26386 }
[email protected]e36e86f2009-12-15 11:55:08387#endif // OS_POSIX
[email protected]9610ef242009-11-18 02:41:26388 process.Close();
[email protected]30935362012-06-28 21:26:23389#endif // defined(OS_ANDROID)
[email protected]9610ef242009-11-18 02:41:26390 }
391
392 Client* client_;
[email protected]d04e7662010-10-10 22:24:48393 BrowserThread::ID client_thread_id_;
[email protected]9610ef242009-11-18 02:41:26394 base::Process process_;
[email protected]f3c1d3c2011-07-25 18:50:48395 base::TerminationStatus termination_status_;
396 int exit_code_;
[email protected]9610ef242009-11-18 02:41:26397 bool starting_;
[email protected]358cb8e2011-05-25 02:12:45398 // Controls whether the child process should be terminated on browser
399 // shutdown. Default behavior is to terminate the child.
400 bool terminate_child_on_shutdown_;
[email protected]30935362012-06-28 21:26:23401#if defined(OS_ANDROID)
402 // The fd to close after creating the process.
403 int ipcfd_;
404#elif defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]9610ef242009-11-18 02:41:26405 bool zygote_;
[email protected]fb1277e82009-11-21 20:32:30406#endif
[email protected]9610ef242009-11-18 02:41:26407};
408
409
[email protected]fb1277e82009-11-21 20:32:30410ChildProcessLauncher::ChildProcessLauncher(
411#if defined(OS_WIN)
[email protected]2dec8ec2013-02-07 19:20:34412 const base::FilePath& exposed_dir,
[email protected]fb1277e82009-11-21 20:32:30413#elif defined(OS_POSIX)
[email protected]7c4ea142010-01-26 05:15:42414 bool use_zygote,
[email protected]a82af392012-02-24 04:40:20415 const base::EnvironmentVector& environ,
[email protected]fb1277e82009-11-21 20:32:30416 int ipcfd,
[email protected]9610ef242009-11-18 02:41:26417#endif
[email protected]fb1277e82009-11-21 20:32:30418 CommandLine* cmd_line,
[email protected]40da3e0c2012-10-24 22:03:38419 int child_process_id,
[email protected]fb1277e82009-11-21 20:32:30420 Client* client) {
421 context_ = new Context();
422 context_->Launch(
423#if defined(OS_WIN)
424 exposed_dir,
[email protected]30935362012-06-28 21:26:23425#elif defined(OS_ANDROID)
426 ipcfd,
[email protected]fb1277e82009-11-21 20:32:30427#elif defined(OS_POSIX)
[email protected]7c4ea142010-01-26 05:15:42428 use_zygote,
[email protected]fb1277e82009-11-21 20:32:30429 environ,
430 ipcfd,
431#endif
432 cmd_line,
[email protected]40da3e0c2012-10-24 22:03:38433 child_process_id,
[email protected]fb1277e82009-11-21 20:32:30434 client);
[email protected]9610ef242009-11-18 02:41:26435}
436
437ChildProcessLauncher::~ChildProcessLauncher() {
438 context_->ResetClient();
439}
440
441bool ChildProcessLauncher::IsStarting() {
442 return context_->starting_;
443}
444
445base::ProcessHandle ChildProcessLauncher::GetHandle() {
446 DCHECK(!context_->starting_);
447 return context_->process_.handle();
448}
449
[email protected]443b80e2010-12-14 00:42:23450base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
[email protected]c7691de2012-12-06 08:31:51451 bool known_dead,
[email protected]443b80e2010-12-14 00:42:23452 int* exit_code) {
[email protected]cd69619b2010-05-05 02:41:38453 base::ProcessHandle handle = context_->process_.handle();
[email protected]f3c1d3c2011-07-25 18:50:48454 if (handle == base::kNullProcessHandle) {
455 // Process is already gone, so return the cached termination status.
456 if (exit_code)
457 *exit_code = context_->exit_code_;
458 return context_->termination_status_;
459 }
[email protected]ffb69732012-02-08 17:33:23460#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]cd69619b2010-05-05 02:41:38461 if (context_->zygote_) {
[email protected]c2c68b1f2012-02-25 00:29:15462 context_->termination_status_ = ZygoteHostImpl::GetInstance()->
[email protected]c7691de2012-12-06 08:31:51463 GetTerminationStatus(handle, known_dead, &context_->exit_code_);
[email protected]cd69619b2010-05-05 02:41:38464 } else
465#endif
466 {
[email protected]f3c1d3c2011-07-25 18:50:48467 context_->termination_status_ =
468 base::GetTerminationStatus(handle, &context_->exit_code_);
[email protected]cd69619b2010-05-05 02:41:38469 }
470
[email protected]f3c1d3c2011-07-25 18:50:48471 if (exit_code)
472 *exit_code = context_->exit_code_;
473
[email protected]443b80e2010-12-14 00:42:23474 // POSIX: If the process crashed, then the kernel closed the socket
475 // for it and so the child has already died by the time we get
476 // here. Since GetTerminationStatus called waitpid with WNOHANG,
477 // it'll reap the process. However, if GetTerminationStatus didn't
478 // reap the child (because it was still running), we'll need to
[email protected]cd69619b2010-05-05 02:41:38479 // Terminate via ProcessWatcher. So we can't close the handle here.
[email protected]f3c1d3c2011-07-25 18:50:48480 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
[email protected]cd69619b2010-05-05 02:41:38481 context_->process_.Close();
482
[email protected]f3c1d3c2011-07-25 18:50:48483 return context_->termination_status_;
[email protected]9610ef242009-11-18 02:41:26484}
485
486void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
[email protected]3e55e212011-03-24 19:45:02487 BrowserThread::PostTask(
488 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
[email protected]037edb52011-11-15 21:14:06489 base::Bind(
[email protected]3e55e212011-03-24 19:45:02490 &ChildProcessLauncher::Context::SetProcessBackgrounded,
[email protected]e2024782011-09-07 20:20:51491 GetHandle(), background));
[email protected]9610ef242009-11-18 02:41:26492}
[email protected]358cb8e2011-05-25 02:12:45493
494void ChildProcessLauncher::SetTerminateChildOnShutdown(
495 bool terminate_on_shutdown) {
496 if (context_)
497 context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
498}
[email protected]130757672012-10-24 00:26:19499
500} // namespace content