blob: 5d7a304e67e0edc18048df5a252ce10f7e033481 [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
dcheng59716272016-04-09 05:19:087#include <memory>
danakje3de838f2015-12-03 01:49:408#include <utility>
9
[email protected]037edb52011-11-15 21:14:0610#include "base/bind.h"
[email protected]9610ef242009-11-18 02:41:2611#include "base/command_line.h"
thestigb7aad54f2014-09-05 18:25:3912#include "base/files/file_util.h"
agrievefd2d44ab2015-06-19 04:33:0313#include "base/i18n/icu_util.h"
[email protected]9610ef242009-11-18 02:41:2614#include "base/logging.h"
[email protected]323fdc312013-02-25 18:44:2615#include "base/metrics/histogram.h"
rockotb3b0dfa02016-02-26 22:43:2816#include "base/process/launch.h"
[email protected]dd4b51262013-07-25 21:38:2317#include "base/process/process.h"
ben03b7b9d2015-11-15 12:13:0918#include "base/strings/string_number_conversions.h"
[email protected]20305ec2011-01-21 04:55:5219#include "base/synchronization/lock.h"
[email protected]34b99632011-01-01 01:01:0620#include "base/threading/thread.h"
avib7348942015-12-25 20:57:1021#include "build/build_config.h"
[email protected]87f3c082011-10-19 18:07:4422#include "content/public/browser/content_browser_client.h"
[email protected]b3aabd342012-06-04 19:33:5623#include "content/public/common/content_descriptors.h"
[email protected]c08950d22011-10-13 22:20:2924#include "content/public/common/content_switches.h"
[email protected]b39ef1cb2011-10-25 04:46:5525#include "content/public/common/result_codes.h"
[email protected]121e61382014-03-13 11:35:1526#include "content/public/common/sandboxed_process_launcher_delegate.h"
rockote8b8da42016-03-02 06:20:2327#include "mojo/edk/embedder/embedder.h"
amistryb6138912016-05-31 01:54:1228#include "mojo/edk/embedder/named_platform_channel_pair.h"
29#include "mojo/edk/embedder/platform_channel_pair.h"
rockote8b8da42016-03-02 06:20:2330#include "mojo/edk/embedder/scoped_platform_handle.h"
[email protected]9610ef242009-11-18 02:41:2631
32#if defined(OS_WIN)
[email protected]57999812013-02-24 05:40:5233#include "base/files/file_path.h"
rockote8b8da42016-03-02 06:20:2334#include "base/win/scoped_handle.h"
35#include "base/win/win_util.h"
[email protected]34f48682013-03-20 00:30:1836#include "content/common/sandbox_win.h"
[email protected]e25b04c92012-10-23 20:05:0637#include "content/public/common/sandbox_init.h"
wfh3adf87d2016-05-03 23:26:0638#include "sandbox/win/src/sandbox_types.h"
[email protected]e63c4d72011-05-31 22:38:2939#elif defined(OS_MACOSX)
rsesekdba84112015-09-18 19:22:0740#include "content/browser/bootstrap_sandbox_manager_mac.h"
[email protected]ed0fbe62011-06-23 18:32:1141#include "content/browser/mach_broker_mac.h"
[email protected]f5bcd0f2014-06-10 14:50:4142#include "sandbox/mac/bootstrap_sandbox.h"
rsesek408d2ee52015-09-18 01:18:0443#include "sandbox/mac/pre_exec_delegate.h"
[email protected]30935362012-06-28 21:26:2344#elif defined(OS_ANDROID)
45#include "base/android/jni_android.h"
[email protected]5e44a142013-03-19 09:48:3946#include "content/browser/android/child_process_launcher_android.h"
[email protected]e63c4d72011-05-31 22:38:2947#elif defined(OS_POSIX)
[email protected]3b63f8f42011-03-28 01:54:1548#include "base/memory/singleton.h"
[email protected]a01efd22011-03-01 00:38:3249#include "content/browser/renderer_host/render_sandbox_host_linux.h"
kerrnelafd49a83b2016-01-22 21:16:1550#include "content/browser/zygote_host/zygote_communication_linux.h"
[email protected]13d6b3c2012-07-24 01:31:3151#include "content/browser/zygote_host/zygote_host_impl_linux.h"
[email protected]a0c900e2013-09-11 18:16:1052#include "content/common/child_process_sandbox_support_impl_linux.h"
kerrnelafd49a83b2016-01-22 21:16:1553#include "content/public/browser/zygote_handle_linux.h"
[email protected]9610ef242009-11-18 02:41:2654#endif
55
[email protected]fb1277e82009-11-21 20:32:3056#if defined(OS_POSIX)
[email protected]613eef62012-11-09 23:46:5457#include "base/posix/global_descriptors.h"
morritad95714f2014-10-01 02:37:2458#include "content/browser/file_descriptor_info_impl.h"
agrievefd2d44ab2015-06-19 04:33:0359#include "gin/v8_initializer.h"
[email protected]fb1277e82009-11-21 20:32:3060#endif
61
[email protected]130757672012-10-24 00:26:1962namespace content {
[email protected]631bb742011-11-02 11:29:3963
sievers954e37a2015-03-28 01:50:2464namespace {
[email protected]9610ef242009-11-18 02:41:2665
kerrnelafd49a83b2016-01-22 21:16:1566typedef base::Callback<void(ZygoteHandle,
tkentdd53cf7322015-03-23 00:54:5067#if defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:2468 base::ScopedFD,
rockote8b8da42016-03-02 06:20:2369 base::ScopedFD,
tkentdd53cf7322015-03-23 00:54:5070#endif
wfh3adf87d2016-05-03 23:26:0671 base::Process,
72 int)> NotifyCallback;
tkentdd53cf7322015-03-23 00:54:5073
sievers954e37a2015-03-28 01:50:2474void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
75 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:2376 // Log the launch time, separating out the first one (which will likely be
77 // slower due to the rest of the browser initializing at the same time).
78 static bool done_first_launch = false;
79 if (done_first_launch) {
80 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
81 } else {
82 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
83 done_first_launch = true;
84 }
85}
86
sievers954e37a2015-03-28 01:50:2487#if defined(OS_ANDROID)
88// TODO(sievers): Remove this by defining better what happens on what
89// thread in the corresponding Java code.
90void OnChildProcessStartedAndroid(const NotifyCallback& callback,
91 BrowserThread::ID client_thread_id,
92 const base::TimeTicks begin_launch_time,
93 base::ScopedFD ipcfd,
rockote8b8da42016-03-02 06:20:2394 base::ScopedFD mojo_fd,
sievers954e37a2015-03-28 01:50:2495 base::ProcessHandle handle) {
wfh3adf87d2016-05-03 23:26:0696 int launch_result = (handle == base::kNullProcessHandle)
97 ? LAUNCH_RESULT_FAILURE
98 : LAUNCH_RESULT_SUCCESS;
sievers954e37a2015-03-28 01:50:2499 // This can be called on the launcher thread or UI thread.
100 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
101 BrowserThread::PostTask(
102 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
103 base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
104
wfh3adf87d2016-05-03 23:26:06105 base::Closure callback_on_client_thread(base::Bind(
106 callback, nullptr, base::Passed(&ipcfd), base::Passed(&mojo_fd),
107 base::Passed(base::Process(handle)), launch_result));
sievers954e37a2015-03-28 01:50:24108 if (BrowserThread::CurrentlyOn(client_thread_id)) {
109 callback_on_client_thread.Run();
110 } else {
111 BrowserThread::PostTask(
112 client_thread_id, FROM_HERE, callback_on_client_thread);
thestig774686b2015-09-15 19:34:31113 }
sievers954e37a2015-03-28 01:50:24114}
115#endif
116
117void LaunchOnLauncherThread(const NotifyCallback& callback,
118 BrowserThread::ID client_thread_id,
119 int child_process_id,
120 SandboxedProcessLauncherDelegate* delegate,
121#if defined(OS_ANDROID)
122 base::ScopedFD ipcfd,
123#endif
rockote8b8da42016-03-02 06:20:23124 mojo::edk::ScopedPlatformHandle client_handle,
sievers954e37a2015-03-28 01:50:24125 base::CommandLine* cmd_line) {
126 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
dcheng59716272016-04-09 05:19:08127 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
kerrnelafd49a83b2016-01-22 21:16:15128#if !defined(OS_ANDROID)
129 ZygoteHandle zygote = nullptr;
wfh3adf87d2016-05-03 23:26:06130 int launch_result = LAUNCH_RESULT_FAILURE;
kerrnelafd49a83b2016-01-22 21:16:15131#endif
rvargas7951bf62014-11-14 04:09:23132#if defined(OS_WIN)
133 bool launch_elevated = delegate->ShouldLaunchElevated();
rvargas7951bf62014-11-14 04:09:23134#elif defined(OS_MACOSX)
135 base::EnvironmentMap env = delegate->GetEnvironment();
136 base::ScopedFD ipcfd = delegate->TakeIpcFd();
sievers954e37a2015-03-28 01:50:24137#elif defined(OS_POSIX) && !defined(OS_ANDROID)
rvargas7951bf62014-11-14 04:09:23138 base::EnvironmentMap env = delegate->GetEnvironment();
139 base::ScopedFD ipcfd = delegate->TakeIpcFd();
140#endif
dcheng59716272016-04-09 05:19:08141 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
rvargas7951bf62014-11-14 04:09:23142 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
143
rvargas3e5d4452014-11-24 19:30:02144 base::Process process;
rvargas0bf966a2015-01-10 04:16:33145#if defined(OS_WIN)
rvargas7951bf62014-11-14 04:09:23146 if (launch_elevated) {
amistryb6138912016-05-31 01:54:12147 // When establishing a Mojo connection, the pipe path has already been added
148 // to the command line.
rvargas7951bf62014-11-14 04:09:23149 base::LaunchOptions options;
150 options.start_hidden = true;
rvargas6293e5b2014-12-01 22:53:09151 process = base::LaunchElevatedProcess(*cmd_line, options);
rvargas7951bf62014-11-14 04:09:23152 } else {
rockote8b8da42016-03-02 06:20:23153 base::HandlesToInheritVector handles;
154 handles.push_back(client_handle.get().handle);
155 cmd_line->AppendSwitchASCII(
156 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch,
157 base::UintToString(base::win::HandleToUint32(handles[0])));
wfh3adf87d2016-05-03 23:26:06158 launch_result =
159 StartSandboxedProcess(delegate, cmd_line, handles, &process);
rvargas7951bf62014-11-14 04:09:23160 }
161#elif defined(OS_POSIX)
162 std::string process_type =
163 cmd_line->GetSwitchValueASCII(switches::kProcessType);
dcheng59716272016-04-09 05:19:08164 std::unique_ptr<FileDescriptorInfo> files_to_register(
rvargas7951bf62014-11-14 04:09:23165 FileDescriptorInfoImpl::Create());
166
rockote8b8da42016-03-02 06:20:23167 base::ScopedFD mojo_fd(client_handle.release().handle);
168 DCHECK(mojo_fd.is_valid());
169
rvargas7951bf62014-11-14 04:09:23170#if defined(OS_ANDROID)
sammce4d0abd2016-03-07 22:38:04171 if (ipcfd.get() != -1)
172 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
rockote8b8da42016-03-02 06:20:23173 files_to_register->Share(kMojoIPCChannel, mojo_fd.get());
rvargas7951bf62014-11-14 04:09:23174#else
sammce4d0abd2016-03-07 22:38:04175 if (ipcfd.get() != -1)
176 files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd));
rockote8b8da42016-03-02 06:20:23177 files_to_register->Transfer(kMojoIPCChannel, std::move(mojo_fd));
rvargas7951bf62014-11-14 04:09:23178#endif
rvargas7951bf62014-11-14 04:09:23179#endif
180
agrievefd2d44ab2015-06-19 04:33:03181#if defined(OS_POSIX) && !defined(OS_MACOSX)
mek39ae21592015-06-16 22:30:38182 std::map<int, base::MemoryMappedFile::Region> regions;
183 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
agrieve05398f52015-06-24 18:59:00184 *cmd_line, child_process_id, files_to_register.get()
185#if defined(OS_ANDROID)
186 , &regions
187#endif
188 );
agrievefd2d44ab2015-06-19 04:33:03189#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
tobiasjsb20016272016-02-10 11:54:12190 bool snapshot_loaded = false;
191#if defined(OS_ANDROID)
192 base::MemoryMappedFile::Region region;
193 auto maybe_register = [&region, &regions, &files_to_register](int key,
194 int fd) {
195 if (fd != -1) {
196 files_to_register->Share(key, fd);
197 regions.insert(std::make_pair(key, region));
198 }
199 };
200 maybe_register(
michaelbai020375882016-06-21 16:08:15201 kV8NativesDataDescriptor,
202 gin::V8Initializer::GetOpenNativesFileForChildProcesses(&region));
tobiasjsb20016272016-02-10 11:54:12203 maybe_register(
204 kV8SnapshotDataDescriptor32,
205 gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(&region, true));
206 maybe_register(
207 kV8SnapshotDataDescriptor64,
208 gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(&region, false));
209
210 snapshot_loaded = true;
211#else
agrievefd2d44ab2015-06-19 04:33:03212 base::PlatformFile natives_pf =
213 gin::V8Initializer::GetOpenNativesFileForChildProcesses(
214 &regions[kV8NativesDataDescriptor]);
215 DCHECK_GE(natives_pf, 0);
216 files_to_register->Share(kV8NativesDataDescriptor, natives_pf);
mek39ae21592015-06-16 22:30:38217
agrievefd2d44ab2015-06-19 04:33:03218 base::MemoryMappedFile::Region snapshot_region;
219 base::PlatformFile snapshot_pf =
220 gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(
221 &snapshot_region);
222 // Failure to load the V8 snapshot is not necessarily an error. V8 can start
223 // up (slower) without the snapshot.
224 if (snapshot_pf != -1) {
tobiasjsb20016272016-02-10 11:54:12225 snapshot_loaded = true;
agrievefd2d44ab2015-06-19 04:33:03226 files_to_register->Share(kV8SnapshotDataDescriptor, snapshot_pf);
227 regions.insert(std::make_pair(kV8SnapshotDataDescriptor, snapshot_region));
228 }
tobiasjsb20016272016-02-10 11:54:12229#endif
agrievefd2d44ab2015-06-19 04:33:03230
231 if (process_type != switches::kZygoteProcess) {
232 cmd_line->AppendSwitch(::switches::kV8NativesPassedByFD);
tobiasjsb20016272016-02-10 11:54:12233 if (snapshot_loaded) {
agrievefd2d44ab2015-06-19 04:33:03234 cmd_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
235 }
236 }
237#endif // defined(V8_USE_EXTERNAL_STARTUP_DATA)
238#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
239
240#if defined(OS_ANDROID)
241 files_to_register->Share(
242 kAndroidICUDataDescriptor,
243 base::i18n::GetIcuDataFileHandle(&regions[kAndroidICUDataDescriptor]));
244
245 // Android WebView runs in single process, ensure that we never get here
246 // when running in single process mode.
247 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
erikcorryc94eff12015-06-08 11:29:16248
rvargas7951bf62014-11-14 04:09:23249 StartChildProcess(
danakje3de838f2015-12-03 01:49:40250 cmd_line->argv(), child_process_id, std::move(files_to_register), regions,
sievers954e37a2015-03-28 01:50:24251 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
rockote8b8da42016-03-02 06:20:23252 begin_launch_time, base::Passed(&ipcfd),
253 base::Passed(&mojo_fd)));
rvargas7951bf62014-11-14 04:09:23254
255#elif defined(OS_POSIX)
rvargas7951bf62014-11-14 04:09:23256 // We need to close the client end of the IPC channel to reliably detect
257 // child termination.
258
259#if !defined(OS_MACOSX)
kerrnelafd49a83b2016-01-22 21:16:15260 ZygoteHandle* zygote_handle = delegate->GetZygote();
261 // If |zygote_handle| is null, a zygote should not be used.
262 if (zygote_handle) {
263 // This code runs on the PROCESS_LAUNCHER thread so race conditions are not
264 // an issue with the lazy initialization.
265 if (*zygote_handle == nullptr) {
266 *zygote_handle = CreateZygote();
267 }
268 zygote = *zygote_handle;
269 base::ProcessHandle handle = zygote->ForkRequest(
danakje3de838f2015-12-03 01:49:40270 cmd_line->argv(), std::move(files_to_register), process_type);
rvargas0bf966a2015-01-10 04:16:33271 process = base::Process(handle);
rvargas7951bf62014-11-14 04:09:23272 } else
273 // Fall through to the normal posix case below when we're not zygoting.
274#endif // !defined(OS_MACOSX)
275 {
276 // Convert FD mapping to FileHandleMappingVector
277 base::FileHandleMappingVector fds_to_map =
278 files_to_register->GetMappingWithIDAdjustment(
279 base::GlobalDescriptors::kBaseDescriptor);
280
281#if !defined(OS_MACOSX)
282 if (process_type == switches::kRendererProcess) {
283 const int sandbox_fd =
284 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
285 fds_to_map.push_back(std::make_pair(
286 sandbox_fd,
287 GetSandboxFD()));
288 }
289#endif // defined(OS_MACOSX)
290
291 // Actually launch the app.
292 base::LaunchOptions options;
293 options.environ = env;
294 options.fds_to_remap = &fds_to_map;
295
296#if defined(OS_MACOSX)
297 // Hold the MachBroker lock for the duration of LaunchProcess. The child
298 // will send its task port to the parent almost immediately after startup.
299 // The Mach message will be delivered to the parent, but updating the
300 // record of the launch will wait until after the placeholder PID is
301 // inserted below. This ensures that while the child process may send its
302 // port to the parent prior to the parent leaving LaunchProcess, the
303 // order in which the record in MachBroker is updated is correct.
304 MachBroker* broker = MachBroker::GetInstance();
305 broker->GetLock().Acquire();
306
307 // Make sure the MachBroker is running, and inform it to expect a
308 // check-in from the new process.
309 broker->EnsureRunning();
310
rsesekdba84112015-09-18 19:22:07311 const SandboxType sandbox_type = delegate->GetSandboxType();
dcheng59716272016-04-09 05:19:08312 std::unique_ptr<sandbox::PreExecDelegate> pre_exec_delegate;
rsesekdba84112015-09-18 19:22:07313 if (BootstrapSandboxManager::ShouldEnable()) {
314 BootstrapSandboxManager* sandbox_manager =
315 BootstrapSandboxManager::GetInstance();
316 if (sandbox_manager->EnabledForSandbox(sandbox_type)) {
dchengf26eed32016-01-13 10:58:14317 pre_exec_delegate = sandbox_manager->sandbox()->NewClient(sandbox_type);
rsesekdba84112015-09-18 19:22:07318 }
rvargas7951bf62014-11-14 04:09:23319 }
rsesek408d2ee52015-09-18 01:18:04320 options.pre_exec_delegate = pre_exec_delegate.get();
rvargas7951bf62014-11-14 04:09:23321#endif // defined(OS_MACOSX)
322
rvargas0bf966a2015-01-10 04:16:33323 process = base::LaunchProcess(*cmd_line, options);
rvargas7951bf62014-11-14 04:09:23324
325#if defined(OS_MACOSX)
rsesek408d2ee52015-09-18 01:18:04326 if (process.IsValid()) {
rvargas960db882015-01-24 00:27:25327 broker->AddPlaceholderForPid(process.Pid(), child_process_id);
rsesek408d2ee52015-09-18 01:18:04328 } else {
329 if (pre_exec_delegate) {
rsesekdba84112015-09-18 19:22:07330 BootstrapSandboxManager::GetInstance()->sandbox()->RevokeToken(
rsesek408d2ee52015-09-18 01:18:04331 pre_exec_delegate->sandbox_token());
332 }
333 }
rvargas7951bf62014-11-14 04:09:23334
335 // After updating the broker, release the lock and let the child's
336 // messasge be processed on the broker's thread.
337 broker->GetLock().Release();
338#endif // defined(OS_MACOSX)
339 }
340#endif // else defined(OS_POSIX)
341#if !defined(OS_ANDROID)
sievers954e37a2015-03-28 01:50:24342 if (process.IsValid()) {
wfh3adf87d2016-05-03 23:26:06343 launch_result = LAUNCH_RESULT_SUCCESS;
sievers954e37a2015-03-28 01:50:24344 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
345 begin_launch_time);
346 }
347 BrowserThread::PostTask(client_thread_id, FROM_HERE,
wfh3adf87d2016-05-03 23:26:06348 base::Bind(callback, zygote, base::Passed(&process),
349 launch_result));
rvargas7951bf62014-11-14 04:09:23350#endif // !defined(OS_ANDROID)
351}
352
kerrnelafd49a83b2016-01-22 21:16:15353void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) {
sievers954e37a2015-03-28 01:50:24354 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
rvargas7951bf62014-11-14 04:09:23355#if defined(OS_ANDROID)
356 VLOG(1) << "ChromeProcess: Stopping process with handle "
357 << process.Handle();
358 StopChildProcess(process.Handle());
359#else
360 // Client has gone away, so just kill the process. Using exit code 0
361 // means that UMA won't treat this as a crash.
rvargaseedb7632015-03-09 23:53:45362 process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
rvargas7951bf62014-11-14 04:09:23363 // On POSIX, we must additionally reap the child.
364#if defined(OS_POSIX)
365#if !defined(OS_MACOSX)
366 if (zygote) {
367 // If the renderer was created via a zygote, we have to proxy the reaping
368 // through the zygote process.
kerrnelafd49a83b2016-01-22 21:16:15369 zygote->EnsureProcessTerminated(process.Handle());
rvargas7951bf62014-11-14 04:09:23370 } else
371#endif // !OS_MACOSX
danakje3de838f2015-12-03 01:49:40372 base::EnsureProcessTerminated(std::move(process));
rvargas7951bf62014-11-14 04:09:23373#endif // OS_POSIX
374#endif // defined(OS_ANDROID)
375}
376
sievers954e37a2015-03-28 01:50:24377void SetProcessBackgroundedOnLauncherThread(base::Process process,
378 bool background) {
379 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
shrike77144012015-10-02 02:46:58380 if (process.CanBackgroundProcesses()) {
381 process.SetProcessBackgrounded(background);
382 }
sievers954e37a2015-03-28 01:50:24383#if defined(OS_ANDROID)
384 SetChildProcessInForeground(process.Handle(), !background);
385#endif
386}
387
ben03b7b9d2015-11-15 12:13:09388} // namespace
[email protected]9610ef242009-11-18 02:41:26389
[email protected]fb1277e82009-11-21 20:32:30390ChildProcessLauncher::ChildProcessLauncher(
[email protected]34f48682013-03-20 00:30:18391 SandboxedProcessLauncherDelegate* delegate,
[email protected]479278702014-08-11 20:32:09392 base::CommandLine* cmd_line,
[email protected]40da3e0c2012-10-24 22:03:38393 int child_process_id,
sievers954e37a2015-03-28 01:50:24394 Client* client,
amistry6ad1e812016-06-06 05:36:30395 const std::string& mojo_child_token,
rockot229fb28e2016-06-16 04:46:16396 const mojo::edk::ProcessErrorCallback& process_error_callback,
sievers954e37a2015-03-28 01:50:24397 bool terminate_on_shutdown)
398 : client_(client),
399 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
400 exit_code_(RESULT_CODE_NORMAL_EXIT),
kerrnelafd49a83b2016-01-22 21:16:15401 zygote_(nullptr),
sievers954e37a2015-03-28 01:50:24402 starting_(true),
rockot229fb28e2016-06-16 04:46:16403 process_error_callback_(process_error_callback),
sievers954e37a2015-03-28 01:50:24404#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
405 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
406 defined(UNDEFINED_SANITIZER)
407 terminate_child_on_shutdown_(false),
408#else
409 terminate_child_on_shutdown_(terminate_on_shutdown),
410#endif
amistry6ad1e812016-06-06 05:36:30411 mojo_child_token_(mojo_child_token),
sievers954e37a2015-03-28 01:50:24412 weak_factory_(this) {
413 DCHECK(CalledOnValidThread());
414 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
415 Launch(delegate, cmd_line, child_process_id);
[email protected]9610ef242009-11-18 02:41:26416}
417
418ChildProcessLauncher::~ChildProcessLauncher() {
sievers954e37a2015-03-28 01:50:24419 DCHECK(CalledOnValidThread());
420 if (process_.IsValid() && terminate_child_on_shutdown_) {
421 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
422 // don't this on the UI/IO threads.
423 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
424 base::Bind(&TerminateOnLauncherThread, zygote_,
425 base::Passed(&process_)));
426 }
427}
428
429void ChildProcessLauncher::Launch(
430 SandboxedProcessLauncherDelegate* delegate,
431 base::CommandLine* cmd_line,
432 int child_process_id) {
433 DCHECK(CalledOnValidThread());
434
435#if defined(OS_ANDROID)
436 // Android only supports renderer, sandboxed utility and gpu.
437 std::string process_type =
438 cmd_line->GetSwitchValueASCII(switches::kProcessType);
439 CHECK(process_type == switches::kGpuProcess ||
440 process_type == switches::kRendererProcess ||
hshi11e97112015-08-29 00:14:36441#if defined(ENABLE_PLUGINS)
442 process_type == switches::kPpapiPluginProcess ||
443#endif
sievers954e37a2015-03-28 01:50:24444 process_type == switches::kUtilityProcess)
445 << "Unsupported process type: " << process_type;
446
447 // Non-sandboxed utility or renderer process are currently not supported.
448 DCHECK(process_type == switches::kGpuProcess ||
449 !cmd_line->HasSwitch(switches::kNoSandbox));
450
451 // We need to close the client end of the IPC channel to reliably detect
452 // child termination. We will close this fd after we create the child
453 // process which is asynchronous on Android.
454 base::ScopedFD ipcfd(delegate->TakeIpcFd().release());
455#endif
456 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
457 weak_factory_.GetWeakPtr(),
458 terminate_child_on_shutdown_));
amistryb6138912016-05-31 01:54:12459 mojo::edk::ScopedPlatformHandle client_handle;
460#if defined(OS_WIN)
461 if (delegate->ShouldLaunchElevated()) {
462 mojo::edk::NamedPlatformChannelPair named_pair;
463 mojo_host_platform_handle_ = named_pair.PassServerHandle();
464 named_pair.PrepareToPassClientHandleToChildProcess(cmd_line);
465 } else
466#endif
467 {
468 mojo::edk::PlatformChannelPair channel_pair;
469 mojo_host_platform_handle_ = channel_pair.PassServerHandle();
470 client_handle = channel_pair.PassClientHandle();
471 }
sievers954e37a2015-03-28 01:50:24472 BrowserThread::PostTask(
473 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
474 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
475 child_process_id, delegate,
476#if defined(OS_ANDROID)
477 base::Passed(&ipcfd),
478#endif
rockote8b8da42016-03-02 06:20:23479 base::Passed(&client_handle), cmd_line));
sievers954e37a2015-03-28 01:50:24480}
481
482void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
483 DCHECK(CalledOnValidThread());
484#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
485 if (zygote_) {
kerrnelafd49a83b2016-01-22 21:16:15486 termination_status_ = zygote_->GetTerminationStatus(
487 process_.Handle(), known_dead, &exit_code_);
sievers954e37a2015-03-28 01:50:24488 } else if (known_dead) {
489 termination_status_ =
490 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
491 } else {
492#elif defined(OS_MACOSX)
493 if (known_dead) {
494 termination_status_ =
495 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
496 } else {
497#elif defined(OS_ANDROID)
498 if (IsChildProcessOomProtected(process_.Handle())) {
499 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
500 } else {
501#else
502 {
503#endif
504 termination_status_ =
505 base::GetTerminationStatus(process_.Handle(), &exit_code_);
506 }
507}
508
509void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
510 DCHECK(CalledOnValidThread());
511 base::Process to_pass = process_.Duplicate();
512 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
513 base::Bind(&SetProcessBackgroundedOnLauncherThread,
514 base::Passed(&to_pass), background));
515}
516
517void ChildProcessLauncher::DidLaunch(
518 base::WeakPtr<ChildProcessLauncher> instance,
519 bool terminate_on_shutdown,
kerrnelafd49a83b2016-01-22 21:16:15520 ZygoteHandle zygote,
sievers954e37a2015-03-28 01:50:24521#if defined(OS_ANDROID)
522 base::ScopedFD ipcfd,
rockote8b8da42016-03-02 06:20:23523 base::ScopedFD mojo_fd,
sievers954e37a2015-03-28 01:50:24524#endif
wfh3adf87d2016-05-03 23:26:06525 base::Process process,
526 int error_code) {
sievers954e37a2015-03-28 01:50:24527 if (!process.IsValid())
528 LOG(ERROR) << "Failed to launch child process";
529
sievers954e37a2015-03-28 01:50:24530 if (instance.get()) {
531 instance->Notify(zygote,
532#if defined(OS_ANDROID)
danakje3de838f2015-12-03 01:49:40533 std::move(ipcfd),
sievers954e37a2015-03-28 01:50:24534#endif
wfh3adf87d2016-05-03 23:26:06535 std::move(process),
536 error_code);
sievers954e37a2015-03-28 01:50:24537 } else {
sievers954e37a2015-03-28 01:50:24538 if (process.IsValid() && terminate_on_shutdown) {
539 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
540 // don't this on the UI/IO threads.
541 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
542 base::Bind(&TerminateOnLauncherThread, zygote,
543 base::Passed(&process)));
544 }
545 }
546}
547
kerrnelafd49a83b2016-01-22 21:16:15548void ChildProcessLauncher::Notify(ZygoteHandle zygote,
sievers954e37a2015-03-28 01:50:24549#if defined(OS_ANDROID)
kerrnelafd49a83b2016-01-22 21:16:15550 base::ScopedFD ipcfd,
sievers954e37a2015-03-28 01:50:24551#endif
wfh3adf87d2016-05-03 23:26:06552 base::Process process,
553 int error_code) {
sievers954e37a2015-03-28 01:50:24554 DCHECK(CalledOnValidThread());
555 starting_ = false;
danakje3de838f2015-12-03 01:49:40556 process_ = std::move(process);
sievers954e37a2015-03-28 01:50:24557
rockote8b8da42016-03-02 06:20:23558 if (process_.IsValid()) {
559 // Set up Mojo IPC to the new process.
560 mojo::edk::ChildProcessLaunched(process_.Handle(),
amistry6ad1e812016-06-06 05:36:30561 std::move(mojo_host_platform_handle_),
rockot229fb28e2016-06-16 04:46:16562 mojo_child_token_,
563 process_error_callback_);
rockote8b8da42016-03-02 06:20:23564 }
565
sievers954e37a2015-03-28 01:50:24566#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
567 zygote_ = zygote;
568#endif
569 if (process_.IsValid()) {
sievers954e37a2015-03-28 01:50:24570 client_->OnProcessLaunched();
571 } else {
amistry6ad1e812016-06-06 05:36:30572 mojo::edk::ChildProcessLaunchFailed(mojo_child_token_);
wfh0d9532a2015-09-02 23:18:58573 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED;
wfh3adf87d2016-05-03 23:26:06574 client_->OnProcessLaunchFailed(error_code);
sievers954e37a2015-03-28 01:50:24575 }
[email protected]9610ef242009-11-18 02:41:26576}
577
578bool ChildProcessLauncher::IsStarting() {
sievers954e37a2015-03-28 01:50:24579 // TODO(crbug.com/469248): This fails in some tests.
580 // DCHECK(CalledOnValidThread());
581 return starting_;
[email protected]9610ef242009-11-18 02:41:26582}
583
rvargas079d1842014-10-17 22:32:16584const base::Process& ChildProcessLauncher::GetProcess() const {
sievers954e37a2015-03-28 01:50:24585 // TODO(crbug.com/469248): This fails in some tests.
586 // DCHECK(CalledOnValidThread());
587 return process_;
[email protected]9610ef242009-11-18 02:41:26588}
589
[email protected]443b80e2010-12-14 00:42:23590base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
[email protected]c7691de2012-12-06 08:31:51591 bool known_dead,
[email protected]443b80e2010-12-14 00:42:23592 int* exit_code) {
sievers954e37a2015-03-28 01:50:24593 DCHECK(CalledOnValidThread());
594 if (!process_.IsValid()) {
[email protected]f3c1d3c2011-07-25 18:50:48595 // Process is already gone, so return the cached termination status.
596 if (exit_code)
sievers954e37a2015-03-28 01:50:24597 *exit_code = exit_code_;
598 return termination_status_;
[email protected]cd69619b2010-05-05 02:41:38599 }
600
sievers954e37a2015-03-28 01:50:24601 UpdateTerminationStatus(known_dead);
[email protected]f3c1d3c2011-07-25 18:50:48602 if (exit_code)
sievers954e37a2015-03-28 01:50:24603 *exit_code = exit_code_;
[email protected]f3c1d3c2011-07-25 18:50:48604
[email protected]443b80e2010-12-14 00:42:23605 // POSIX: If the process crashed, then the kernel closed the socket
606 // for it and so the child has already died by the time we get
607 // here. Since GetTerminationStatus called waitpid with WNOHANG,
608 // it'll reap the process. However, if GetTerminationStatus didn't
609 // reap the child (because it was still running), we'll need to
[email protected]cd69619b2010-05-05 02:41:38610 // Terminate via ProcessWatcher. So we can't close the handle here.
sievers954e37a2015-03-28 01:50:24611 if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
612 process_.Close();
[email protected]cd69619b2010-05-05 02:41:38613
sievers954e37a2015-03-28 01:50:24614 return termination_status_;
[email protected]358cb8e2011-05-25 02:12:45615}
[email protected]130757672012-10-24 00:26:19616
lfg06aac852015-03-23 22:36:10617ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
618 Client* client) {
sievers954e37a2015-03-28 01:50:24619 Client* ret = client_;
620 client_ = client;
621 return ret;
lfg06aac852015-03-23 22:36:10622}
623
[email protected]130757672012-10-24 00:26:19624} // namespace content