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