blob: 09b77ee552cbdf27453fd6ffd35fcbc0cc36b40b [file] [log] [blame]
[email protected]7f070d42011-03-09 20:25:321// Copyright (c) 2011 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]df8e899b2011-02-22 22:58:225#include "content/browser/browser_child_process_host.h"
[email protected]d27893f62010-07-03 05:47:426
7#include "base/command_line.h"
8#include "base/file_path.h"
[email protected]d3c6c0d72010-12-09 08:15:049#include "base/lazy_instance.h"
[email protected]d27893f62010-07-03 05:47:4210#include "base/logging.h"
[email protected]835d7c82010-10-14 04:38:3811#include "base/metrics/histogram.h"
[email protected]d27893f62010-07-03 05:47:4212#include "base/path_service.h"
13#include "base/process_util.h"
[email protected]7286e3fc2011-07-19 22:13:2414#include "base/stl_util.h"
[email protected]d27893f62010-07-03 05:47:4215#include "base/string_util.h"
[email protected]33047f12011-12-01 23:20:2016#include "content/browser/profiler_message_filter.h"
[email protected]50285ff2011-03-11 23:10:5617#include "content/browser/renderer_host/resource_message_filter.h"
[email protected]d61e0962011-03-18 22:27:5518#include "content/browser/trace_message_filter.h"
[email protected]105303e2011-03-14 22:16:1019#include "content/common/plugin_messages.h"
[email protected]c38831a12011-10-28 12:44:4920#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4421#include "content/public/browser/content_browser_client.h"
[email protected]c38831a12011-10-28 12:44:4922#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1623#include "content/public/browser/notification_types.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]d27893f62010-07-03 05:47:4226
[email protected]a3a7e2c2011-09-16 23:07:0527#if defined(OS_WIN)
28#include "base/synchronization/waitable_event.h"
[email protected]3838ca12011-11-02 14:37:1529#else
30#include "base/bind.h"
31#endif
[email protected]a3a7e2c2011-09-16 23:07:0532
[email protected]631bb742011-11-02 11:29:3933using content::BrowserThread;
34
[email protected]d27893f62010-07-03 05:47:4235namespace {
36
37typedef std::list<BrowserChildProcessHost*> ChildProcessList;
[email protected]6de0fd1d2011-11-15 13:31:4938static base::LazyInstance<ChildProcessList> g_child_process_list =
39 LAZY_INSTANCE_INITIALIZER;
[email protected]d27893f62010-07-03 05:47:4240
41// The NotificationTask is used to notify about plugin process connection/
42// disconnection. It is needed because the notifications in the
43// NotificationService must happen in the main thread.
44class ChildNotificationTask : public Task {
45 public:
46 ChildNotificationTask(
[email protected]432115822011-07-10 15:52:2747 int notification_type, ChildProcessInfo* info)
[email protected]d27893f62010-07-03 05:47:4248 : notification_type_(notification_type), info_(*info) { }
49
50 virtual void Run() {
[email protected]ad50def52011-10-19 23:17:0751 content::NotificationService::current()->
52 Notify(notification_type_, content::NotificationService::AllSources(),
[email protected]6c2381d2011-10-19 02:52:5353 content::Details<ChildProcessInfo>(&info_));
[email protected]d27893f62010-07-03 05:47:4254 }
55
56 private:
[email protected]432115822011-07-10 15:52:2757 int notification_type_;
[email protected]d27893f62010-07-03 05:47:4258 ChildProcessInfo info_;
59};
60
61} // namespace
62
[email protected]38917fe2011-04-06 17:29:1263BrowserChildProcessHost::BrowserChildProcessHost(
[email protected]bd5d6cf2011-12-01 00:39:1264 content::ProcessType type)
[email protected]38917fe2011-04-06 17:29:1265 : ChildProcessInfo(type, -1),
[email protected]a3a7e2c2011-09-16 23:07:0566 ALLOW_THIS_IN_INITIALIZER_LIST(client_(this)),
[email protected]3838ca12011-11-02 14:37:1567#if !defined(OS_WIN)
68 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
69#endif
[email protected]a3a7e2c2011-09-16 23:07:0570 disconnect_was_alive_(false) {
[email protected]38917fe2011-04-06 17:29:1271 AddFilter(new TraceMessageFilter);
[email protected]33047f12011-12-01 23:20:2072 AddFilter(new ProfilerMessageFilter);
[email protected]38917fe2011-04-06 17:29:1273
74 g_child_process_list.Get().push_back(this);
75}
76
[email protected]d27893f62010-07-03 05:47:4277BrowserChildProcessHost::~BrowserChildProcessHost() {
[email protected]d3c6c0d72010-12-09 08:15:0478 g_child_process_list.Get().remove(this);
[email protected]d27893f62010-07-03 05:47:4279}
80
81// static
[email protected]d27893f62010-07-03 05:47:4282void BrowserChildProcessHost::TerminateAll() {
83 // Make a copy since the ChildProcessHost dtor mutates the original list.
[email protected]d3c6c0d72010-12-09 08:15:0484 ChildProcessList copy = g_child_process_list.Get();
[email protected]d27893f62010-07-03 05:47:4285 STLDeleteElements(&copy);
86}
87
88void BrowserChildProcessHost::Launch(
89#if defined(OS_WIN)
90 const FilePath& exposed_dir,
91#elif defined(OS_POSIX)
92 bool use_zygote,
93 const base::environment_vector& environ,
94#endif
95 CommandLine* cmd_line) {
[email protected]b80f68432011-05-02 17:22:3096
97 content::GetContentClient()->browser()->AppendExtraCommandLineSwitches(
98 cmd_line, id());
99
[email protected]d27893f62010-07-03 05:47:42100 child_process_.reset(new ChildProcessLauncher(
101#if defined(OS_WIN)
102 exposed_dir,
103#elif defined(OS_POSIX)
104 use_zygote,
105 environ,
[email protected]2ce26c432011-09-19 17:08:12106 channel()->TakeClientFileDescriptor(),
[email protected]d27893f62010-07-03 05:47:42107#endif
108 cmd_line,
109 &client_));
110}
111
[email protected]5d84d012010-12-02 17:17:21112base::ProcessHandle BrowserChildProcessHost::GetChildProcessHandle() const {
113 DCHECK(child_process_.get())
114 << "Requesting a child process handle before launching.";
115 DCHECK(child_process_->GetHandle())
116 << "Requesting a child process handle before launch has completed OK.";
117 return child_process_->GetHandle();
118}
119
[email protected]d27893f62010-07-03 05:47:42120void BrowserChildProcessHost::ForceShutdown() {
[email protected]d3c6c0d72010-12-09 08:15:04121 g_child_process_list.Get().remove(this);
[email protected]d27893f62010-07-03 05:47:42122 ChildProcessHost::ForceShutdown();
123}
124
[email protected]358cb8e2011-05-25 02:12:45125void BrowserChildProcessHost::SetTerminateChildOnShutdown(
126 bool terminate_on_shutdown) {
127 child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown);
128}
129
[email protected]432115822011-07-10 15:52:27130void BrowserChildProcessHost::Notify(int type) {
[email protected]d04e7662010-10-10 22:24:48131 BrowserThread::PostTask(
132 BrowserThread::UI, FROM_HERE, new ChildNotificationTask(type, this));
[email protected]d27893f62010-07-03 05:47:42133}
134
[email protected]443b80e2010-12-14 00:42:23135base::TerminationStatus BrowserChildProcessHost::GetChildTerminationStatus(
136 int* exit_code) {
137 return child_process_->GetChildTerminationStatus(exit_code);
[email protected]d27893f62010-07-03 05:47:42138}
139
[email protected]0d6e9bd2011-10-18 04:29:16140void BrowserChildProcessHost::OnChannelConnected(int32 peer_pid) {
141 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED);
142}
143
[email protected]3838ca12011-11-02 14:37:15144// The ChildProcessHost default implementation calls OnChildDied() always but at
145// this layer and below we need to have the final child process exit code to
146// properly bucket crashes vs kills. On Windows we can do this if we wait until
147// the process handle is signaled; on the rest of the platforms, we schedule a
148// delayed task to wait for an exit code. However, this means that this method
149// may be called twice: once from the actual channel error and once from
150// OnWaitableEventSignaled() or the delayed task.
[email protected]a3a7e2c2011-09-16 23:07:05151void BrowserChildProcessHost::OnChildDisconnected() {
152 DCHECK(handle() != base::kNullProcessHandle);
153 int exit_code;
154 base::TerminationStatus status = GetChildTerminationStatus(&exit_code);
155 switch (status) {
156 case base::TERMINATION_STATUS_PROCESS_CRASHED:
157 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: {
158 OnProcessCrashed(exit_code);
159 // Report that this child process crashed.
160 Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED);
[email protected]2f603cd2011-10-24 22:27:01161 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed",
[email protected]bd5d6cf2011-12-01 00:39:12162 this->type(),
163 content::PROCESS_TYPE_MAX);
[email protected]a3a7e2c2011-09-16 23:07:05164 if (disconnect_was_alive_) {
[email protected]2f603cd2011-10-24 22:27:01165 UMA_HISTOGRAM_ENUMERATION("ChildProcess.CrashedWasAlive",
[email protected]bd5d6cf2011-12-01 00:39:12166 this->type(),
167 content::PROCESS_TYPE_MAX);
[email protected]12fed812011-09-16 05:47:29168 }
[email protected]a3a7e2c2011-09-16 23:07:05169 break;
[email protected]12fed812011-09-16 05:47:29170 }
[email protected]a3a7e2c2011-09-16 23:07:05171 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
172 OnProcessWasKilled(exit_code);
173 // Report that this child process was killed.
174 Notify(content::NOTIFICATION_CHILD_PROCESS_WAS_KILLED);
[email protected]2f603cd2011-10-24 22:27:01175 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed",
[email protected]bd5d6cf2011-12-01 00:39:12176 this->type(),
177 content::PROCESS_TYPE_MAX);
[email protected]a3a7e2c2011-09-16 23:07:05178 if (disconnect_was_alive_) {
[email protected]2f603cd2011-10-24 22:27:01179 UMA_HISTOGRAM_ENUMERATION("ChildProcess.KilledWasAlive",
[email protected]bd5d6cf2011-12-01 00:39:12180 this->type(),
181 content::PROCESS_TYPE_MAX);
[email protected]a3a7e2c2011-09-16 23:07:05182 }
183 break;
184 }
185 case base::TERMINATION_STATUS_STILL_RUNNING: {
[email protected]3838ca12011-11-02 14:37:15186 // Exit code not yet available. Ensure we don't wait forever for an exit
187 // code.
188 if (disconnect_was_alive_) {
189 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive",
[email protected]bd5d6cf2011-12-01 00:39:12190 this->type(),
191 content::PROCESS_TYPE_MAX);
[email protected]3838ca12011-11-02 14:37:15192 break;
193 }
[email protected]a3a7e2c2011-09-16 23:07:05194 disconnect_was_alive_ = true;
195#if defined(OS_WIN)
196 child_watcher_.StartWatching(new base::WaitableEvent(handle()), this);
[email protected]a3a7e2c2011-09-16 23:07:05197#else
[email protected]3838ca12011-11-02 14:37:15198 // On non-Windows platforms, give the child process some time to die after
199 // disconnecting the channel so that the exit code and termination status
200 // become available. This is best effort -- if the process doesn't die
201 // within the time limit, this object gets destroyed.
202 const int kExitCodeWaitMs = 250;
203 MessageLoop::current()->PostDelayedTask(
204 FROM_HERE,
205 base::Bind(&BrowserChildProcessHost::OnChildDisconnected,
206 task_factory_.GetWeakPtr()),
207 kExitCodeWaitMs);
[email protected]a3a7e2c2011-09-16 23:07:05208#endif
[email protected]3838ca12011-11-02 14:37:15209 return;
[email protected]a3a7e2c2011-09-16 23:07:05210 }
211
212 default:
213 break;
[email protected]d27893f62010-07-03 05:47:42214 }
[email protected]80bb87e2011-10-19 22:06:18215 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected",
[email protected]bd5d6cf2011-12-01 00:39:12216 this->type(),
217 content::PROCESS_TYPE_MAX);
[email protected]a3a7e2c2011-09-16 23:07:05218 // Notify in the main loop of the disconnection.
219 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED);
220 OnChildDied();
221}
222
223// The child process handle has been signaled so the exit code is finally
224// available. Unfortunately STILL_ACTIVE (0x103) is a valid exit code in
225// which case we should not call OnChildDisconnected() or else we will be
226// waiting forever.
227void BrowserChildProcessHost::OnWaitableEventSignaled(
228 base::WaitableEvent* waitable_event) {
229#if defined (OS_WIN)
230 unsigned long exit_code = 0;
231 GetExitCodeProcess(waitable_event->Release(), &exit_code);
232 delete waitable_event;
233 if (exit_code == STILL_ACTIVE)
234 OnChildDied();
235 BrowserChildProcessHost::OnChildDisconnected();
236#endif
[email protected]d27893f62010-07-03 05:47:42237}
238
[email protected]8e2b6472010-12-15 22:19:48239void BrowserChildProcessHost::ShutdownStarted() {
240 // Must remove the process from the list now, in case it gets used for a
241 // new instance before our watcher tells us that the process terminated.
242 g_child_process_list.Get().remove(this);
[email protected]d27893f62010-07-03 05:47:42243}
244
245BrowserChildProcessHost::ClientHook::ClientHook(BrowserChildProcessHost* host)
246 : host_(host) {
247}
248
249void BrowserChildProcessHost::ClientHook::OnProcessLaunched() {
[email protected]bf84c582011-08-23 03:17:02250 if (!host_->child_process_->GetHandle()) {
[email protected]d27893f62010-07-03 05:47:42251 host_->OnChildDied();
252 return;
253 }
[email protected]bf84c582011-08-23 03:17:02254 host_->set_handle(host_->child_process_->GetHandle());
[email protected]d27893f62010-07-03 05:47:42255 host_->OnProcessLaunched();
256}
257
258BrowserChildProcessHost::Iterator::Iterator()
[email protected]bd5d6cf2011-12-01 00:39:12259 : all_(true), type_(content::PROCESS_TYPE_UNKNOWN) {
[email protected]d04e7662010-10-10 22:24:48260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
[email protected]d27893f62010-07-03 05:47:42261 "ChildProcessInfo::Iterator must be used on the IO thread.";
[email protected]d3c6c0d72010-12-09 08:15:04262 iterator_ = g_child_process_list.Get().begin();
[email protected]d27893f62010-07-03 05:47:42263}
264
[email protected]bd5d6cf2011-12-01 00:39:12265BrowserChildProcessHost::Iterator::Iterator(content::ProcessType type)
[email protected]d27893f62010-07-03 05:47:42266 : all_(false), type_(type) {
[email protected]d04e7662010-10-10 22:24:48267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
[email protected]d27893f62010-07-03 05:47:42268 "ChildProcessInfo::Iterator must be used on the IO thread.";
[email protected]d3c6c0d72010-12-09 08:15:04269 iterator_ = g_child_process_list.Get().begin();
[email protected]d27893f62010-07-03 05:47:42270 if (!Done() && (*iterator_)->type() != type_)
271 ++(*this);
272}
273
274BrowserChildProcessHost* BrowserChildProcessHost::Iterator::operator++() {
275 do {
276 ++iterator_;
277 if (Done())
278 break;
279
280 if (!all_ && (*iterator_)->type() != type_)
281 continue;
282
283 return *iterator_;
284 } while (true);
285
286 return NULL;
287}
288
289bool BrowserChildProcessHost::Iterator::Done() {
[email protected]d3c6c0d72010-12-09 08:15:04290 return iterator_ == g_child_process_list.Get().end();
[email protected]d27893f62010-07-03 05:47:42291}