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