blob: 8e6bde3b0abb07daf0e2c09253c36dfce86b38e8 [file] [log] [blame]
[email protected]02798a982012-01-27 00:45:331// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]d27893f62010-07-03 05:47:422// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]4c01d4992012-01-23 23:33:015#include "content/browser/browser_child_process_host_impl.h"
[email protected]d27893f62010-07-03 05:47:426
[email protected]2b065f82012-10-18 07:11:167#include "base/base_switches.h"
[email protected]4306c3792011-12-02 01:57:538#include "base/bind.h"
[email protected]d27893f62010-07-03 05:47:429#include "base/command_line.h"
[email protected]57999812013-02-24 05:40:5210#include "base/files/file_path.h"
[email protected]d3c6c0d72010-12-09 08:15:0411#include "base/lazy_instance.h"
[email protected]d27893f62010-07-03 05:47:4212#include "base/logging.h"
[email protected]835d7c82010-10-14 04:38:3813#include "base/metrics/histogram.h"
[email protected]d27893f62010-07-03 05:47:4214#include "base/path_service.h"
[email protected]7286e3fc2011-07-19 22:13:2415#include "base/stl_util.h"
[email protected]10994d132013-06-11 07:16:1816#include "base/strings/string_util.h"
[email protected]162a9fd2013-03-06 20:47:4917#include "base/synchronization/waitable_event.h"
[email protected]83ab4a282012-07-12 18:19:4518#include "content/browser/histogram_message_filter.h"
[email protected]678c0362012-12-05 08:02:4419#include "content/browser/loader/resource_message_filter.h"
[email protected]33047f12011-12-01 23:20:2020#include "content/browser/profiler_message_filter.h"
[email protected]3a85b1f2013-02-01 04:47:4021#include "content/browser/tracing/trace_message_filter.h"
[email protected]4734d0b2011-12-03 07:10:4422#include "content/common/child_process_host_impl.h"
[email protected]4967f792012-01-20 22:14:4023#include "content/public/browser/browser_child_process_host_delegate.h"
[email protected]f4eaf7b92013-02-28 22:00:4024#include "content/public/browser/browser_child_process_observer.h"
[email protected]57999812013-02-24 05:40:5225#include "content/public/browser/browser_thread.h"
[email protected]4306c3792011-12-02 01:57:5326#include "content/public/browser/child_process_data.h"
[email protected]87f3c082011-10-19 18:07:4427#include "content/public/browser/content_browser_client.h"
[email protected]c08950d22011-10-13 22:20:2928#include "content/public/common/content_switches.h"
[email protected]f3b357692013-03-22 05:16:1329#include "content/public/common/process_type.h"
[email protected]b39ef1cb2011-10-25 04:46:5530#include "content/public/common/result_codes.h"
[email protected]d27893f62010-07-03 05:47:4231
[email protected]f1675202012-07-09 15:18:0032#if defined(OS_MACOSX)
[email protected]458433c2012-02-29 23:43:3933#include "content/browser/mach_broker_mac.h"
[email protected]3838ca12011-11-02 14:37:1534#endif
[email protected]a3a7e2c2011-09-16 23:07:0535
[email protected]130757672012-10-24 00:26:1936namespace content {
[email protected]d27893f62010-07-03 05:47:4237namespace {
38
[email protected]4c01d4992012-01-23 23:33:0139static base::LazyInstance<BrowserChildProcessHostImpl::BrowserChildProcessList>
[email protected]4967f792012-01-20 22:14:4040 g_child_process_list = LAZY_INSTANCE_INITIALIZER;
[email protected]d27893f62010-07-03 05:47:4241
[email protected]f4eaf7b92013-02-28 22:00:4042base::LazyInstance<ObserverList<BrowserChildProcessObserver> >
43 g_observers = LAZY_INSTANCE_INITIALIZER;
44
45void NotifyProcessHostConnected(const ChildProcessData& data) {
46 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
47 BrowserChildProcessHostConnected(data));
48}
49
50void NotifyProcessHostDisconnected(const ChildProcessData& data) {
51 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
52 BrowserChildProcessHostDisconnected(data));
53}
54
55void NotifyProcessCrashed(const ChildProcessData& data) {
56 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
57 BrowserChildProcessCrashed(data));
[email protected]4306c3792011-12-02 01:57:5358}
[email protected]d27893f62010-07-03 05:47:4259
60} // namespace
61
[email protected]4967f792012-01-20 22:14:4062BrowserChildProcessHost* BrowserChildProcessHost::Create(
[email protected]f3b357692013-03-22 05:16:1363 int process_type,
[email protected]4967f792012-01-20 22:14:4064 BrowserChildProcessHostDelegate* delegate) {
[email protected]f3b357692013-03-22 05:16:1365 return new BrowserChildProcessHostImpl(process_type, delegate);
[email protected]4967f792012-01-20 22:14:4066}
67
[email protected]458433c2012-02-29 23:43:3968#if defined(OS_MACOSX)
69base::ProcessMetrics::PortProvider* BrowserChildProcessHost::GetPortProvider() {
70 return MachBroker::GetInstance();
71}
72#endif
73
[email protected]f4eaf7b92013-02-28 22:00:4074// static
[email protected]4c01d4992012-01-23 23:33:0175BrowserChildProcessHostImpl::BrowserChildProcessList*
76 BrowserChildProcessHostImpl::GetIterator() {
[email protected]4967f792012-01-20 22:14:4077 return g_child_process_list.Pointer();
78}
79
[email protected]f4eaf7b92013-02-28 22:00:4080// static
81void BrowserChildProcessHostImpl::AddObserver(
82 BrowserChildProcessObserver* observer) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 g_observers.Get().AddObserver(observer);
85}
86
87// static
88void BrowserChildProcessHostImpl::RemoveObserver(
89 BrowserChildProcessObserver* observer) {
90 // TODO(phajdan.jr): Check thread after fixing http://crbug.com/167126.
91 g_observers.Get().RemoveObserver(observer);
92}
93
[email protected]4c01d4992012-01-23 23:33:0194BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
[email protected]f3b357692013-03-22 05:16:1395 int process_type,
[email protected]4967f792012-01-20 22:14:4096 BrowserChildProcessHostDelegate* delegate)
[email protected]f3b357692013-03-22 05:16:1397 : data_(process_type),
[email protected]9dd90152013-08-02 22:09:1398 delegate_(delegate),
99 power_monitor_message_broadcaster_(this) {
[email protected]4734d0b2011-12-03 07:10:44100 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId();
[email protected]4306c3792011-12-02 01:57:53101
[email protected]4734d0b2011-12-03 07:10:44102 child_process_host_.reset(ChildProcessHost::Create(this));
[email protected]ba780c12013-10-01 17:07:06103 AddFilter(new TraceMessageFilter);
104 AddFilter(new ProfilerMessageFilter(process_type));
105 AddFilter(new HistogramMessageFilter);
[email protected]38917fe2011-04-06 17:29:12106
107 g_child_process_list.Get().push_back(this);
[email protected]130757672012-10-24 00:26:19108 GetContentClient()->browser()->BrowserChildProcessHostCreated(this);
[email protected]38917fe2011-04-06 17:29:12109}
110
[email protected]4c01d4992012-01-23 23:33:01111BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
[email protected]d3c6c0d72010-12-09 08:15:04112 g_child_process_list.Get().remove(this);
[email protected]162a9fd2013-03-06 20:47:49113
114#if defined(OS_WIN)
115 DeleteProcessWaitableEvent(early_exit_watcher_.GetWatchedEvent());
116#endif
[email protected]d27893f62010-07-03 05:47:42117}
118
119// static
[email protected]4c01d4992012-01-23 23:33:01120void BrowserChildProcessHostImpl::TerminateAll() {
[email protected]4967f792012-01-20 22:14:40121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]f174efd2012-01-17 18:43:33122 // Make a copy since the BrowserChildProcessHost dtor mutates the original
123 // list.
124 BrowserChildProcessList copy = g_child_process_list.Get();
[email protected]5998d9d2012-03-06 04:25:26125 for (BrowserChildProcessList::iterator it = copy.begin();
126 it != copy.end(); ++it) {
127 delete (*it)->delegate(); // ~*HostDelegate deletes *HostImpl.
128 }
[email protected]d27893f62010-07-03 05:47:42129}
130
[email protected]4c01d4992012-01-23 23:33:01131void BrowserChildProcessHostImpl::Launch(
[email protected]d27893f62010-07-03 05:47:42132#if defined(OS_WIN)
[email protected]34f48682013-03-20 00:30:18133 SandboxedProcessLauncherDelegate* delegate,
[email protected]d27893f62010-07-03 05:47:42134#elif defined(OS_POSIX)
135 bool use_zygote,
[email protected]b345c482013-08-30 18:00:39136 const base::EnvironmentMap& environ,
[email protected]d27893f62010-07-03 05:47:42137#endif
138 CommandLine* cmd_line) {
[email protected]4967f792012-01-20 22:14:40139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]b80f68432011-05-02 17:22:30140
[email protected]130757672012-10-24 00:26:19141 GetContentClient()->browser()->AppendExtraCommandLineSwitches(
[email protected]4967f792012-01-20 22:14:40142 cmd_line, data_.id);
[email protected]b80f68432011-05-02 17:22:30143
[email protected]2b065f82012-10-18 07:11:16144 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
145 static const char* kForwardSwitches[] = {
[email protected]2b065f82012-10-18 07:11:16146 switches::kDisableLogging,
147 switches::kEnableDCHECK,
148 switches::kEnableLogging,
149 switches::kLoggingLevel,
[email protected]2bf64a92013-07-11 23:10:40150 switches::kTraceToConsole,
[email protected]2b065f82012-10-18 07:11:16151 switches::kV,
152 switches::kVModule,
[email protected]34f48682013-03-20 00:30:18153#if defined(OS_POSIX)
154 switches::kChildCleanExit,
155#endif
[email protected]c8e8cb942013-09-10 23:36:08156#if defined(OS_WIN)
157 switches::kEnableHighResolutionTime,
158#endif
[email protected]2b065f82012-10-18 07:11:16159 };
160 cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
161 arraysize(kForwardSwitches));
[email protected]719a2052012-07-30 21:00:43162
[email protected]d27893f62010-07-03 05:47:42163 child_process_.reset(new ChildProcessLauncher(
164#if defined(OS_WIN)
[email protected]34f48682013-03-20 00:30:18165 delegate,
[email protected]d27893f62010-07-03 05:47:42166#elif defined(OS_POSIX)
167 use_zygote,
168 environ,
[email protected]4967f792012-01-20 22:14:40169 child_process_host_->TakeClientFileDescriptor(),
[email protected]d27893f62010-07-03 05:47:42170#endif
171 cmd_line,
[email protected]40da3e0c2012-10-24 22:03:38172 data_.id,
[email protected]4967f792012-01-20 22:14:40173 this));
[email protected]d27893f62010-07-03 05:47:42174}
175
[email protected]4c01d4992012-01-23 23:33:01176const ChildProcessData& BrowserChildProcessHostImpl::GetData() const {
[email protected]4967f792012-01-20 22:14:40177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
178 return data_;
179}
180
[email protected]4c01d4992012-01-23 23:33:01181ChildProcessHost* BrowserChildProcessHostImpl::GetHost() const {
[email protected]4967f792012-01-20 22:14:40182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
183 return child_process_host_.get();
184}
185
[email protected]4c01d4992012-01-23 23:33:01186base::ProcessHandle BrowserChildProcessHostImpl::GetHandle() const {
[email protected]4967f792012-01-20 22:14:40187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]5d84d012010-12-02 17:17:21188 DCHECK(child_process_.get())
189 << "Requesting a child process handle before launching.";
190 DCHECK(child_process_->GetHandle())
191 << "Requesting a child process handle before launch has completed OK.";
192 return child_process_->GetHandle();
193}
194
[email protected]4c01d4992012-01-23 23:33:01195void BrowserChildProcessHostImpl::SetName(const string16& name) {
[email protected]4967f792012-01-20 22:14:40196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]f174efd2012-01-17 18:43:33197 data_.name = name;
198}
199
[email protected]4c01d4992012-01-23 23:33:01200void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) {
[email protected]4967f792012-01-20 22:14:40201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]f174efd2012-01-17 18:43:33202 data_.handle = handle;
203}
204
[email protected]4c01d4992012-01-23 23:33:01205void BrowserChildProcessHostImpl::ForceShutdown() {
[email protected]4967f792012-01-20 22:14:40206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]d3c6c0d72010-12-09 08:15:04207 g_child_process_list.Get().remove(this);
[email protected]4cb43102011-12-02 20:24:49208 child_process_host_->ForceShutdown();
[email protected]d27893f62010-07-03 05:47:42209}
210
[email protected]d36860d2013-05-31 00:04:21211void BrowserChildProcessHostImpl::SetBackgrounded(bool backgrounded) {
212 child_process_->SetProcessBackgrounded(backgrounded);
213}
214
[email protected]4c01d4992012-01-23 23:33:01215void BrowserChildProcessHostImpl::SetTerminateChildOnShutdown(
[email protected]4967f792012-01-20 22:14:40216 bool terminate_on_shutdown) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]358cb8e2011-05-25 02:12:45218 child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown);
219}
220
[email protected]ba780c12013-10-01 17:07:06221void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) {
222 child_process_host_->AddFilter(filter->GetFilter());
223}
224
[email protected]f4eaf7b92013-02-28 22:00:40225void BrowserChildProcessHostImpl::NotifyProcessInstanceCreated(
226 const ChildProcessData& data) {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
228 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
229 BrowserChildProcessInstanceCreated(data));
[email protected]d27893f62010-07-03 05:47:42230}
231
[email protected]4c01d4992012-01-23 23:33:01232base::TerminationStatus BrowserChildProcessHostImpl::GetTerminationStatus(
[email protected]547603d2013-08-27 17:59:19233 bool known_dead, int* exit_code) {
[email protected]4967f792012-01-20 22:14:40234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]59383c782013-04-17 16:43:27235 if (!child_process_) // If the delegate doesn't use Launch() helper.
[email protected]4967f792012-01-20 22:14:40236 return base::GetTerminationStatus(data_.handle, exit_code);
[email protected]547603d2013-08-27 17:59:19237 return child_process_->GetChildTerminationStatus(known_dead,
[email protected]c7691de2012-12-06 08:31:51238 exit_code);
[email protected]d27893f62010-07-03 05:47:42239}
240
[email protected]4c01d4992012-01-23 23:33:01241bool BrowserChildProcessHostImpl::OnMessageReceived(
242 const IPC::Message& message) {
[email protected]4967f792012-01-20 22:14:40243 return delegate_->OnMessageReceived(message);
[email protected]4cb43102011-12-02 20:24:49244}
245
[email protected]4c01d4992012-01-23 23:33:01246void BrowserChildProcessHostImpl::OnChannelConnected(int32 peer_pid) {
[email protected]162a9fd2013-03-06 20:47:49247#if defined(OS_WIN)
248 // From this point onward, the exit of the child process is detected by an
249 // error on the IPC channel.
250 DeleteProcessWaitableEvent(early_exit_watcher_.GetWatchedEvent());
251 early_exit_watcher_.StopWatching();
252#endif
253
[email protected]f4eaf7b92013-02-28 22:00:40254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
255 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
256 base::Bind(&NotifyProcessHostConnected, data_));
[email protected]162a9fd2013-03-06 20:47:49257
[email protected]4967f792012-01-20 22:14:40258 delegate_->OnChannelConnected(peer_pid);
259}
260
[email protected]4c01d4992012-01-23 23:33:01261void BrowserChildProcessHostImpl::OnChannelError() {
[email protected]4967f792012-01-20 22:14:40262 delegate_->OnChannelError();
[email protected]0d6e9bd2011-10-18 04:29:16263}
264
[email protected]4c01d4992012-01-23 23:33:01265bool BrowserChildProcessHostImpl::CanShutdown() {
[email protected]4967f792012-01-20 22:14:40266 return delegate_->CanShutdown();
[email protected]4cb43102011-12-02 20:24:49267}
268
[email protected]4c01d4992012-01-23 23:33:01269void BrowserChildProcessHostImpl::OnChildDisconnected() {
[email protected]f4eaf7b92013-02-28 22:00:40270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]6d057a0c2013-07-09 21:12:07271 if (child_process_.get() || data_.handle) {
272 DCHECK(data_.handle != base::kNullProcessHandle);
273 int exit_code;
[email protected]547603d2013-08-27 17:59:19274 base::TerminationStatus status = GetTerminationStatus(
275 true /* known_dead */, &exit_code);
[email protected]6d057a0c2013-07-09 21:12:07276 switch (status) {
277 case base::TERMINATION_STATUS_PROCESS_CRASHED:
278 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: {
279 delegate_->OnProcessCrashed(exit_code);
280 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
281 base::Bind(&NotifyProcessCrashed, data_));
282 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2",
283 data_.process_type,
284 PROCESS_TYPE_MAX);
285 break;
286 }
287 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
288 delegate_->OnProcessCrashed(exit_code);
289 // Report that this child process was killed.
290 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2",
291 data_.process_type,
292 PROCESS_TYPE_MAX);
293 break;
294 }
295 case base::TERMINATION_STATUS_STILL_RUNNING: {
296 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive2",
297 data_.process_type,
298 PROCESS_TYPE_MAX);
299 }
300 default:
301 break;
[email protected]12fed812011-09-16 05:47:29302 }
[email protected]6d057a0c2013-07-09 21:12:07303 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected2",
304 data_.process_type,
305 PROCESS_TYPE_MAX);
[email protected]d27893f62010-07-03 05:47:42306 }
[email protected]f4eaf7b92013-02-28 22:00:40307 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
308 base::Bind(&NotifyProcessHostDisconnected, data_));
[email protected]4967f792012-01-20 22:14:40309 delete delegate_; // Will delete us
[email protected]a3a7e2c2011-09-16 23:07:05310}
311
[email protected]4c01d4992012-01-23 23:33:01312bool BrowserChildProcessHostImpl::Send(IPC::Message* message) {
[email protected]4cb43102011-12-02 20:24:49313 return child_process_host_->Send(message);
314}
315
[email protected]4c01d4992012-01-23 23:33:01316void BrowserChildProcessHostImpl::OnProcessLaunched() {
[email protected]d8c70062013-04-24 00:22:34317 base::ProcessHandle handle = child_process_->GetHandle();
318 if (!handle) {
[email protected]4967f792012-01-20 22:14:40319 delete delegate_; // Will delete us
[email protected]d27893f62010-07-03 05:47:42320 return;
321 }
[email protected]162a9fd2013-03-06 20:47:49322
323#if defined(OS_WIN)
324 // Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
325 // child process exits. This watcher is stopped once the IPC channel is
326 // connected and the exit of the child process is detecter by an error on the
327 // IPC channel thereafter.
328 DCHECK(!early_exit_watcher_.GetWatchedEvent());
329 early_exit_watcher_.StartWatching(
[email protected]d8c70062013-04-24 00:22:34330 new base::WaitableEvent(handle),
[email protected]162a9fd2013-03-06 20:47:49331 base::Bind(&BrowserChildProcessHostImpl::OnProcessExitedEarly,
332 base::Unretained(this)));
333#endif
334
[email protected]d8c70062013-04-24 00:22:34335 data_.handle = handle;
[email protected]4967f792012-01-20 22:14:40336 delegate_->OnProcessLaunched();
[email protected]d27893f62010-07-03 05:47:42337}
[email protected]130757672012-10-24 00:26:19338
[email protected]162a9fd2013-03-06 20:47:49339#if defined(OS_WIN)
340
341void BrowserChildProcessHostImpl::DeleteProcessWaitableEvent(
342 base::WaitableEvent* event) {
343 if (!event)
344 return;
345
346 // The WaitableEvent does not own the process handle so ensure it does not
347 // close it.
348 event->Release();
349
350 delete event;
351}
352
353void BrowserChildProcessHostImpl::OnProcessExitedEarly(
354 base::WaitableEvent* event) {
355 DeleteProcessWaitableEvent(event);
356 OnChildDisconnected();
357}
358
359#endif
360
[email protected]130757672012-10-24 00:26:19361} // namespace content