[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / browser_child_process_host_impl.cc
blob0755e8b3b4d291a76f10da107f47b5aa595d93a9
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/browser_child_process_host_impl.h"
7 #include "base/base_switches.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/debug/dump_without_crashing.h"
11 #include "base/files/file_path.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_util.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "content/browser/histogram_message_filter.h"
20 #include "content/browser/loader/resource_message_filter.h"
21 #include "content/browser/profiler_message_filter.h"
22 #include "content/browser/tracing/trace_message_filter.h"
23 #include "content/common/child_process_host_impl.h"
24 #include "content/public/browser/browser_child_process_host_delegate.h"
25 #include "content/public/browser/browser_child_process_observer.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/child_process_data.h"
28 #include "content/public/browser/content_browser_client.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/process_type.h"
31 #include "content/public/common/result_codes.h"
33 #if defined(OS_MACOSX)
34 #include "content/browser/mach_broker_mac.h"
35 #endif
37 namespace content {
38 namespace {
40 static base::LazyInstance<BrowserChildProcessHostImpl::BrowserChildProcessList>
41 g_child_process_list = LAZY_INSTANCE_INITIALIZER;
43 base::LazyInstance<base::ObserverList<BrowserChildProcessObserver>>
44 g_observers = LAZY_INSTANCE_INITIALIZER;
46 void NotifyProcessHostConnected(const ChildProcessData& data) {
47 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
48 BrowserChildProcessHostConnected(data));
51 void NotifyProcessHostDisconnected(const ChildProcessData& data) {
52 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
53 BrowserChildProcessHostDisconnected(data));
56 void NotifyProcessCrashed(const ChildProcessData& data, int exit_code) {
57 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
58 BrowserChildProcessCrashed(data, exit_code));
61 void NotifyProcessKilled(const ChildProcessData& data, int exit_code) {
62 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
63 BrowserChildProcessKilled(data, exit_code));
66 } // namespace
68 BrowserChildProcessHost* BrowserChildProcessHost::Create(
69 content::ProcessType process_type,
70 BrowserChildProcessHostDelegate* delegate) {
71 return new BrowserChildProcessHostImpl(process_type, delegate);
74 BrowserChildProcessHost* BrowserChildProcessHost::FromID(int child_process_id) {
75 DCHECK_CURRENTLY_ON(BrowserThread::IO);
76 BrowserChildProcessHostImpl::BrowserChildProcessList* process_list =
77 g_child_process_list.Pointer();
78 for (BrowserChildProcessHostImpl* host : *process_list) {
79 if (host->GetData().id == child_process_id)
80 return host;
82 return nullptr;
85 #if defined(OS_MACOSX)
86 base::ProcessMetrics::PortProvider* BrowserChildProcessHost::GetPortProvider() {
87 return MachBroker::GetInstance();
89 #endif
91 // static
92 BrowserChildProcessHostImpl::BrowserChildProcessList*
93 BrowserChildProcessHostImpl::GetIterator() {
94 return g_child_process_list.Pointer();
97 // static
98 void BrowserChildProcessHostImpl::AddObserver(
99 BrowserChildProcessObserver* observer) {
100 DCHECK_CURRENTLY_ON(BrowserThread::UI);
101 g_observers.Get().AddObserver(observer);
104 // static
105 void BrowserChildProcessHostImpl::RemoveObserver(
106 BrowserChildProcessObserver* observer) {
107 // TODO(phajdan.jr): Check thread after fixing http://crbug.com/167126.
108 g_observers.Get().RemoveObserver(observer);
111 BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
112 content::ProcessType process_type,
113 BrowserChildProcessHostDelegate* delegate)
114 : data_(process_type),
115 delegate_(delegate),
116 power_monitor_message_broadcaster_(this) {
117 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId();
119 child_process_host_.reset(ChildProcessHost::Create(this));
120 AddFilter(new TraceMessageFilter(data_.id));
121 AddFilter(new ProfilerMessageFilter(process_type));
122 AddFilter(new HistogramMessageFilter);
124 g_child_process_list.Get().push_back(this);
125 GetContentClient()->browser()->BrowserChildProcessHostCreated(this);
127 power_monitor_message_broadcaster_.Init();
130 BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
131 g_child_process_list.Get().remove(this);
134 // static
135 void BrowserChildProcessHostImpl::TerminateAll() {
136 DCHECK_CURRENTLY_ON(BrowserThread::IO);
137 // Make a copy since the BrowserChildProcessHost dtor mutates the original
138 // list.
139 BrowserChildProcessList copy = g_child_process_list.Get();
140 for (BrowserChildProcessList::iterator it = copy.begin();
141 it != copy.end(); ++it) {
142 delete (*it)->delegate(); // ~*HostDelegate deletes *HostImpl.
146 void BrowserChildProcessHostImpl::Launch(
147 SandboxedProcessLauncherDelegate* delegate,
148 base::CommandLine* cmd_line,
149 bool terminate_on_shutdown) {
150 DCHECK_CURRENTLY_ON(BrowserThread::IO);
152 GetContentClient()->browser()->AppendExtraCommandLineSwitches(
153 cmd_line, data_.id);
155 const base::CommandLine& browser_command_line =
156 *base::CommandLine::ForCurrentProcess();
157 static const char* kForwardSwitches[] = {
158 switches::kDisableLogging,
159 switches::kEnableLogging,
160 switches::kIPCConnectionTimeout,
161 switches::kLoggingLevel,
162 switches::kTraceToConsole,
163 switches::kV,
164 switches::kVModule,
166 cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
167 arraysize(kForwardSwitches));
169 child_process_.reset(new ChildProcessLauncher(
170 delegate,
171 cmd_line,
172 data_.id,
173 this,
174 terminate_on_shutdown));
177 const ChildProcessData& BrowserChildProcessHostImpl::GetData() const {
178 DCHECK_CURRENTLY_ON(BrowserThread::IO);
179 return data_;
182 ChildProcessHost* BrowserChildProcessHostImpl::GetHost() const {
183 DCHECK_CURRENTLY_ON(BrowserThread::IO);
184 return child_process_host_.get();
187 const base::Process& BrowserChildProcessHostImpl::GetProcess() const {
188 DCHECK_CURRENTLY_ON(BrowserThread::IO);
189 DCHECK(child_process_.get())
190 << "Requesting a child process handle before launching.";
191 DCHECK(child_process_->GetProcess().IsValid())
192 << "Requesting a child process handle before launch has completed OK.";
193 return child_process_->GetProcess();
196 void BrowserChildProcessHostImpl::SetName(const base::string16& name) {
197 DCHECK_CURRENTLY_ON(BrowserThread::IO);
198 data_.name = name;
201 void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) {
202 DCHECK_CURRENTLY_ON(BrowserThread::IO);
203 data_.handle = handle;
206 ServiceRegistry* BrowserChildProcessHostImpl::GetServiceRegistry() {
207 DCHECK_CURRENTLY_ON(BrowserThread::IO);
208 return delegate_->GetServiceRegistry();
211 void BrowserChildProcessHostImpl::ForceShutdown() {
212 DCHECK_CURRENTLY_ON(BrowserThread::IO);
213 g_child_process_list.Get().remove(this);
214 child_process_host_->ForceShutdown();
217 void BrowserChildProcessHostImpl::SetBackgrounded(bool backgrounded) {
218 child_process_->SetProcessBackgrounded(backgrounded);
221 void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) {
222 child_process_host_->AddFilter(filter->GetFilter());
225 void BrowserChildProcessHostImpl::NotifyProcessInstanceCreated(
226 const ChildProcessData& data) {
227 DCHECK_CURRENTLY_ON(BrowserThread::UI);
228 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
229 BrowserChildProcessInstanceCreated(data));
232 void BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
233 int process_type) {
234 UMA_HISTOGRAM_ENUMERATION("ChildProcess.BadMessgeTerminated", process_type,
235 PROCESS_TYPE_MAX);
238 base::TerminationStatus BrowserChildProcessHostImpl::GetTerminationStatus(
239 bool known_dead, int* exit_code) {
240 DCHECK_CURRENTLY_ON(BrowserThread::IO);
241 if (!child_process_) // If the delegate doesn't use Launch() helper.
242 return base::GetTerminationStatus(data_.handle, exit_code);
243 return child_process_->GetChildTerminationStatus(known_dead,
244 exit_code);
247 bool BrowserChildProcessHostImpl::OnMessageReceived(
248 const IPC::Message& message) {
249 return delegate_->OnMessageReceived(message);
252 void BrowserChildProcessHostImpl::OnChannelConnected(int32 peer_pid) {
253 #if defined(OS_WIN)
254 // From this point onward, the exit of the child process is detected by an
255 // error on the IPC channel.
256 early_exit_watcher_.StopWatching();
257 #endif
259 DCHECK_CURRENTLY_ON(BrowserThread::IO);
260 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
261 base::Bind(&NotifyProcessHostConnected, data_));
263 delegate_->OnChannelConnected(peer_pid);
266 void BrowserChildProcessHostImpl::OnChannelError() {
267 delegate_->OnChannelError();
270 void BrowserChildProcessHostImpl::OnBadMessageReceived(
271 const IPC::Message& message) {
272 HistogramBadMessageTerminated(data_.process_type);
273 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
274 switches::kDisableKillAfterBadIPC)) {
275 return;
277 LOG(ERROR) << "Terminating child process for bad IPC message of type "
278 << message.type();
280 // Create a memory dump. This will contain enough stack frames to work out
281 // what the bad message was.
282 base::debug::DumpWithoutCrashing();
284 child_process_->GetProcess().Terminate(RESULT_CODE_KILLED_BAD_MESSAGE, false);
287 bool BrowserChildProcessHostImpl::CanShutdown() {
288 return delegate_->CanShutdown();
291 void BrowserChildProcessHostImpl::OnChildDisconnected() {
292 DCHECK_CURRENTLY_ON(BrowserThread::IO);
293 #if defined(OS_WIN)
294 // OnChildDisconnected may be called without OnChannelConnected, so stop the
295 // early exit watcher so GetTerminationStatus can close the process handle.
296 early_exit_watcher_.StopWatching();
297 #endif
298 if (child_process_.get() || data_.handle) {
299 int exit_code;
300 base::TerminationStatus status = GetTerminationStatus(
301 true /* known_dead */, &exit_code);
302 switch (status) {
303 case base::TERMINATION_STATUS_PROCESS_CRASHED:
304 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: {
305 delegate_->OnProcessCrashed(exit_code);
306 BrowserThread::PostTask(
307 BrowserThread::UI, FROM_HERE,
308 base::Bind(&NotifyProcessCrashed, data_, exit_code));
309 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2",
310 data_.process_type,
311 PROCESS_TYPE_MAX);
312 break;
314 #if defined(OS_ANDROID)
315 case base::TERMINATION_STATUS_OOM_PROTECTED:
316 #endif
317 #if defined(OS_CHROMEOS)
318 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
319 #endif
320 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
321 delegate_->OnProcessCrashed(exit_code);
322 BrowserThread::PostTask(
323 BrowserThread::UI, FROM_HERE,
324 base::Bind(&NotifyProcessKilled, data_, exit_code));
325 // Report that this child process was killed.
326 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2",
327 data_.process_type,
328 PROCESS_TYPE_MAX);
329 break;
331 case base::TERMINATION_STATUS_STILL_RUNNING: {
332 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive2",
333 data_.process_type,
334 PROCESS_TYPE_MAX);
336 default:
337 break;
339 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected2",
340 data_.process_type,
341 PROCESS_TYPE_MAX);
342 #if defined(OS_CHROMEOS)
343 if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
344 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2.OOM",
345 data_.process_type,
346 PROCESS_TYPE_MAX);
348 #endif
350 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
351 base::Bind(&NotifyProcessHostDisconnected, data_));
352 delete delegate_; // Will delete us
355 bool BrowserChildProcessHostImpl::Send(IPC::Message* message) {
356 return child_process_host_->Send(message);
359 void BrowserChildProcessHostImpl::OnProcessLaunchFailed() {
360 delegate_->OnProcessLaunchFailed();
361 delete delegate_; // Will delete us
364 void BrowserChildProcessHostImpl::OnProcessLaunched() {
365 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
366 // is fixed.
367 tracked_objects::ScopedTracker tracking_profile(
368 FROM_HERE_WITH_EXPLICIT_FUNCTION(
369 "465841 BrowserChildProcessHostImpl::OnProcessLaunched"));
370 const base::Process& process = child_process_->GetProcess();
371 DCHECK(process.IsValid());
373 #if defined(OS_WIN)
374 // Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
375 // child process exits. This watcher is stopped once the IPC channel is
376 // connected and the exit of the child process is detecter by an error on the
377 // IPC channel thereafter.
378 DCHECK(!early_exit_watcher_.GetWatchedObject());
379 early_exit_watcher_.StartWatching(process.Handle(), this);
380 #endif
382 // TODO(rvargas) crbug.com/417532: Don't store a handle.
383 data_.handle = process.Handle();
384 delegate_->OnProcessLaunched();
387 #if defined(OS_WIN)
389 void BrowserChildProcessHostImpl::OnObjectSignaled(HANDLE object) {
390 OnChildDisconnected();
393 #endif
395 } // namespace content