browser_message_filter.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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.
4
5#include "content/public/browser/browser_message_filter.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/logging.h"
10#include "base/process.h"
11#include "base/process_util.h"
12#include "base/task_runner.h"
13#include "content/public/browser/user_metrics.h"
14#include "content/public/common/result_codes.h"
15#include "ipc/ipc_sync_message.h"
16
17using content::BrowserMessageFilter;
18
19namespace content {
20
21BrowserMessageFilter::BrowserMessageFilter()
22    : channel_(NULL), peer_handle_(base::kNullProcessHandle) {
23}
24
25void BrowserMessageFilter::OnFilterAdded(IPC::Channel* channel) {
26  channel_ = channel;
27}
28
29void BrowserMessageFilter::OnChannelClosing() {
30  channel_ = NULL;
31}
32
33void BrowserMessageFilter::OnChannelConnected(int32 peer_pid) {
34  if (!base::OpenPrivilegedProcessHandle(peer_pid, &peer_handle_)) {
35    NOTREACHED();
36  }
37}
38
39bool BrowserMessageFilter::OnMessageReceived(const IPC::Message& message) {
40  BrowserThread::ID thread = BrowserThread::IO;
41  OverrideThreadForMessage(message, &thread);
42
43  if (thread == BrowserThread::IO) {
44    scoped_refptr<base::TaskRunner> runner =
45        OverrideTaskRunnerForMessage(message);
46    if (runner.get()) {
47      runner->PostTask(
48          FROM_HERE,
49          base::Bind(base::IgnoreResult(&BrowserMessageFilter::DispatchMessage),
50                     this,
51                     message));
52      return true;
53    }
54    return DispatchMessage(message);
55  }
56
57  if (thread == BrowserThread::UI && !CheckCanDispatchOnUI(message, this))
58    return true;
59
60  BrowserThread::PostTask(
61      thread, FROM_HERE,
62      base::Bind(base::IgnoreResult(&BrowserMessageFilter::DispatchMessage),
63                 this, message));
64  return true;
65}
66
67bool BrowserMessageFilter::Send(IPC::Message* message) {
68  if (message->is_sync()) {
69    // We don't support sending synchronous messages from the browser.  If we
70    // really needed it, we can make this class derive from SyncMessageFilter
71    // but it seems better to not allow sending synchronous messages from the
72    // browser, since it might allow a corrupt/malicious renderer to hang us.
73    NOTREACHED() << "Can't send sync message through BrowserMessageFilter!";
74    return false;
75  }
76
77  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
78    BrowserThread::PostTask(
79        BrowserThread::IO,
80        FROM_HERE,
81        base::Bind(base::IgnoreResult(&BrowserMessageFilter::Send), this,
82                   message));
83    return true;
84  }
85
86  if (channel_)
87    return channel_->Send(message);
88
89  delete message;
90  return false;
91}
92
93void BrowserMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
94                                                    BrowserThread::ID* thread) {
95}
96
97base::TaskRunner* BrowserMessageFilter::OverrideTaskRunnerForMessage(
98    const IPC::Message& message) {
99  return NULL;
100}
101
102bool BrowserMessageFilter::CheckCanDispatchOnUI(const IPC::Message& message,
103                                                IPC::Sender* sender) {
104#if defined(OS_WIN)
105  // On Windows there's a potential deadlock with sync messsages going in
106  // a circle from browser -> plugin -> renderer -> browser.
107  // On Linux we can avoid this by avoiding sync messages from browser->plugin.
108  // On Mac we avoid this by not supporting windowed plugins.
109  if (message.is_sync() && !message.is_caller_pumping_messages()) {
110    // NOTE: IF YOU HIT THIS ASSERT, THE SOLUTION IS ALMOST NEVER TO RUN A
111    // NESTED MESSAGE LOOP IN THE RENDERER!!!
112    // That introduces reentrancy which causes hard to track bugs.  You should
113    // find a way to either turn this into an asynchronous message, or one
114    // that can be answered on the IO thread.
115    NOTREACHED() << "Can't send sync messages to UI thread without pumping "
116        "messages in the renderer or else deadlocks can occur if the page "
117        "has windowed plugins! (message type " << message.type() << ")";
118    IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
119    reply->set_reply_error();
120    sender->Send(reply);
121    return false;
122  }
123#endif
124  return true;
125}
126
127void BrowserMessageFilter::BadMessageReceived() {
128  base::KillProcess(peer_handle(), content::RESULT_CODE_KILLED_BAD_MESSAGE,
129                    false);
130}
131
132BrowserMessageFilter::~BrowserMessageFilter() {
133  base::CloseProcessHandle(peer_handle_);
134}
135
136bool BrowserMessageFilter::DispatchMessage(const IPC::Message& message) {
137  bool message_was_ok = true;
138  bool rv = OnMessageReceived(message, &message_was_ok);
139  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) || rv) <<
140      "Must handle messages that were dispatched to another thread!";
141  if (!message_was_ok) {
142    content::RecordAction(UserMetricsAction("BadMessageTerminate_BMF"));
143    BadMessageReceived();
144  }
145
146  return rv;
147}
148
149}  // namespace content
150