| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/extension_message_service.h" | 5 #include "chrome/browser/extensions/extension_message_service.h" |
| 6 | 6 |
| 7 #include "base/atomic_sequence_num.h" |
| 7 #include "base/json/json_writer.h" | 8 #include "base/json/json_writer.h" |
| 8 #include "base/singleton.h" | |
| 9 #include "base/stl_util-inl.h" | 9 #include "base/stl_util-inl.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "chrome/browser/child_process_security_policy.h" | 11 #include "chrome/browser/child_process_security_policy.h" |
| 12 #include "chrome/browser/chrome_thread.h" | |
| 13 #include "chrome/browser/extensions/extension_process_manager.h" | 12 #include "chrome/browser/extensions/extension_process_manager.h" |
| 14 #include "chrome/browser/extensions/extension_tabs_module.h" | 13 #include "chrome/browser/extensions/extension_tabs_module.h" |
| 15 #include "chrome/browser/profile.h" | 14 #include "chrome/browser/profile.h" |
| 16 #include "chrome/browser/renderer_host/render_process_host.h" | 15 #include "chrome/browser/renderer_host/render_process_host.h" |
| 17 #include "chrome/browser/renderer_host/render_view_host.h" | 16 #include "chrome/browser/renderer_host/render_view_host.h" |
| 18 #include "chrome/browser/renderer_host/resource_message_filter.h" | 17 #include "chrome/browser/renderer_host/resource_message_filter.h" |
| 19 #include "chrome/browser/tab_contents/tab_contents.h" | 18 #include "chrome/browser/tab_contents/tab_contents.h" |
| 20 #include "chrome/browser/tab_contents/tab_util.h" | 19 #include "chrome/browser/tab_contents/tab_util.h" |
| 21 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
| 22 #include "chrome/common/notification_service.h" | 21 #include "chrome/common/notification_service.h" |
| 23 #include "chrome/common/render_messages.h" | 22 #include "chrome/common/render_messages.h" |
| 24 | 23 |
| 25 // Since we have 2 ports for every channel, we just index channels by half the | 24 // Since we have 2 ports for every channel, we just index channels by half the |
| 26 // port ID. | 25 // port ID. |
| 27 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) | 26 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) |
| 28 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) | 27 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) |
| 29 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) | 28 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) |
| 30 | 29 |
| 31 // Port1 is always even, port2 is always odd. | 30 // Port1 is always even, port2 is always odd. |
| 32 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) | 31 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) |
| 33 | 32 |
| 34 // Change even to odd and vice versa, to get the other side of a given channel. | 33 // Change even to odd and vice versa, to get the other side of a given channel. |
| 35 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) | 34 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) |
| 36 | 35 |
| 37 struct ExtensionMessageService::MessagePort { | 36 struct ExtensionMessageService::MessagePort { |
| 38 IPC::Message::Sender* sender; | 37 IPC::Message::Sender* sender; |
| 39 int routing_id; | 38 int routing_id; |
| 40 // TODO(mpcomplete): remove this when I track down the crasher. Hopefully | |
| 41 // this guy will show up in some stack traces and potentially give some | |
| 42 // insight. | |
| 43 // http://code.google.com/p/chromium/issues/detail?id=21201 | |
| 44 int debug_info; | |
| 45 | |
| 46 MessagePort(IPC::Message::Sender* sender = NULL, | 39 MessagePort(IPC::Message::Sender* sender = NULL, |
| 47 int routing_id = MSG_ROUTING_CONTROL) : | 40 int routing_id = MSG_ROUTING_CONTROL) : |
| 48 sender(sender), routing_id(routing_id), debug_info(0) {} | 41 sender(sender), routing_id(routing_id) {} |
| 49 }; | 42 }; |
| 50 | 43 |
| 51 struct ExtensionMessageService::MessageChannel { | 44 struct ExtensionMessageService::MessageChannel { |
| 52 ExtensionMessageService::MessagePort opener; | 45 ExtensionMessageService::MessagePort opener; |
| 53 ExtensionMessageService::MessagePort receiver; | 46 ExtensionMessageService::MessagePort receiver; |
| 54 }; | 47 }; |
| 55 | 48 |
| 49 const char ExtensionMessageService::kDispatchOnConnect[] = |
| 50 "Port.dispatchOnConnect"; |
| 51 const char ExtensionMessageService::kDispatchOnDisconnect[] = |
| 52 "Port.dispatchOnDisconnect"; |
| 53 const char ExtensionMessageService::kDispatchOnMessage[] = |
| 54 "Port.dispatchOnMessage"; |
| 55 const char ExtensionMessageService::kDispatchEvent[] = |
| 56 "Event.dispatchJSON"; |
| 56 | 57 |
| 57 namespace { | 58 namespace { |
| 58 | 59 |
| 60 static base::AtomicSequenceNumber g_next_channel_id(base::LINKER_INITIALIZED); |
| 61 |
| 59 static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port, | 62 static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port, |
| 60 int dest_port_id, | 63 int dest_port_id, |
| 61 const std::string& channel_name, | 64 const std::string& channel_name, |
| 62 const std::string& tab_json, | 65 const std::string& tab_json, |
| 63 const std::string& source_extension_id, | 66 const std::string& source_extension_id, |
| 64 const std::string& target_extension_id) { | 67 const std::string& target_extension_id) { |
| 65 ListValue args; | 68 ListValue args; |
| 66 args.Set(0, Value::CreateIntegerValue(dest_port_id)); | 69 args.Set(0, Value::CreateIntegerValue(dest_port_id)); |
| 67 args.Set(1, Value::CreateStringValue(channel_name)); | 70 args.Set(1, Value::CreateStringValue(channel_name)); |
| 68 args.Set(2, Value::CreateStringValue(tab_json)); | 71 args.Set(2, Value::CreateStringValue(tab_json)); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 98 ListValue args; | 101 ListValue args; |
| 99 args.Set(0, Value::CreateStringValue(event_name)); | 102 args.Set(0, Value::CreateStringValue(event_name)); |
| 100 args.Set(1, Value::CreateStringValue(event_args)); | 103 args.Set(1, Value::CreateStringValue(event_args)); |
| 101 port.sender->Send(new ViewMsg_ExtensionMessageInvoke(port.routing_id, | 104 port.sender->Send(new ViewMsg_ExtensionMessageInvoke(port.routing_id, |
| 102 ExtensionMessageService::kDispatchEvent, args, has_incognito_data, | 105 ExtensionMessageService::kDispatchEvent, args, has_incognito_data, |
| 103 event_url)); | 106 event_url)); |
| 104 } | 107 } |
| 105 | 108 |
| 106 } // namespace | 109 } // namespace |
| 107 | 110 |
| 108 const char ExtensionMessageService::kDispatchOnConnect[] = | |
| 109 "Port.dispatchOnConnect"; | |
| 110 const char ExtensionMessageService::kDispatchOnDisconnect[] = | |
| 111 "Port.dispatchOnDisconnect"; | |
| 112 const char ExtensionMessageService::kDispatchOnMessage[] = | |
| 113 "Port.dispatchOnMessage"; | |
| 114 const char ExtensionMessageService::kDispatchEvent[] = | |
| 115 "Event.dispatchJSON"; | |
| 116 | |
| 117 // static | 111 // static |
| 118 std::string ExtensionMessageService::GetPerExtensionEventName( | 112 std::string ExtensionMessageService::GetPerExtensionEventName( |
| 119 const std::string& event_name, const std::string& extension_id) { | 113 const std::string& event_name, const std::string& extension_id) { |
| 120 // This should match the method we use in extension_process_binding.js when | 114 // This should match the method we use in extension_process_binding.js when |
| 121 // setting up the corresponding chrome.Event object. | 115 // setting up the corresponding chrome.Event object. |
| 122 return event_name + "/" + extension_id; | 116 return event_name + "/" + extension_id; |
| 123 } | 117 } |
| 124 | 118 |
| 119 // static |
| 120 void ExtensionMessageService::AllocatePortIdPair(int* port1, int* port2) { |
| 121 int channel_id = g_next_channel_id.GetNext(); |
| 122 int port1_id = channel_id * 2; |
| 123 int port2_id = channel_id * 2 + 1; |
| 124 |
| 125 // Sanity checks to make sure our channel<->port converters are correct. |
| 126 DCHECK(IS_OPENER_PORT_ID(port1_id)); |
| 127 DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id); |
| 128 DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id); |
| 129 DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id)); |
| 130 DCHECK(GET_CHANNEL_ID(port1_id) == channel_id); |
| 131 DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id); |
| 132 DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id); |
| 133 |
| 134 *port1 = port1_id; |
| 135 *port2 = port2_id; |
| 136 } |
| 137 |
| 125 ExtensionMessageService::ExtensionMessageService(Profile* profile) | 138 ExtensionMessageService::ExtensionMessageService(Profile* profile) |
| 126 : profile_(profile), | 139 : profile_(profile), |
| 127 extension_devtools_manager_(NULL), | 140 extension_devtools_manager_(NULL) { |
| 128 next_port_id_(0) { | |
| 129 registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED, | 141 registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED, |
| 130 NotificationService::AllSources()); | 142 NotificationService::AllSources()); |
| 131 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED, | 143 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED, |
| 132 NotificationService::AllSources()); | 144 NotificationService::AllSources()); |
| 133 registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, | 145 registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, |
| 134 NotificationService::AllSources()); | 146 NotificationService::AllSources()); |
| 135 | 147 |
| 136 extension_devtools_manager_ = profile_->GetExtensionDevToolsManager(); | 148 extension_devtools_manager_ = profile_->GetExtensionDevToolsManager(); |
| 137 } | 149 } |
| 138 | 150 |
| 139 ExtensionMessageService::~ExtensionMessageService() { | 151 ExtensionMessageService::~ExtensionMessageService() { |
| 140 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end()); | 152 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end()); |
| 141 channels_.clear(); | 153 channels_.clear(); |
| 142 } | 154 } |
| 143 | 155 |
| 144 void ExtensionMessageService::ProfileDestroyed() { | 156 void ExtensionMessageService::ProfileDestroyed() { |
| 145 profile_ = NULL; | 157 profile_ = NULL; |
| 146 if (!registrar_.IsEmpty()) { | 158 if (!registrar_.IsEmpty()) |
| 147 CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 148 registrar_.RemoveAll(); | 159 registrar_.RemoveAll(); |
| 149 } | |
| 150 } | 160 } |
| 151 | 161 |
| 152 void ExtensionMessageService::AddEventListener(const std::string& event_name, | 162 void ExtensionMessageService::AddEventListener(const std::string& event_name, |
| 153 int render_process_id) { | 163 int render_process_id) { |
| 154 // It is possible that this RenderProcessHost is being destroyed. If that is | 164 // It is possible that this RenderProcessHost is being destroyed. If that is |
| 155 // the case, we'll have already removed his listeners, so do nothing here. | 165 // the case, we'll have already removed his listeners, so do nothing here. |
| 156 RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id); | 166 RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id); |
| 157 if (!rph || rph->ListenersIterator().IsAtEnd()) | 167 if (!rph || rph->ListenersIterator().IsAtEnd()) |
| 158 return; | 168 return; |
| 159 | 169 |
| 160 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 161 DCHECK_EQ(listeners_[event_name].count(render_process_id), 0u) << event_name; | 170 DCHECK_EQ(listeners_[event_name].count(render_process_id), 0u) << event_name; |
| 162 listeners_[event_name].insert(render_process_id); | 171 listeners_[event_name].insert(render_process_id); |
| 163 | 172 |
| 164 if (extension_devtools_manager_.get()) { | 173 if (extension_devtools_manager_.get()) { |
| 165 extension_devtools_manager_->AddEventListener(event_name, | 174 extension_devtools_manager_->AddEventListener(event_name, |
| 166 render_process_id); | 175 render_process_id); |
| 167 } | 176 } |
| 168 } | 177 } |
| 169 | 178 |
| 170 void ExtensionMessageService::RemoveEventListener(const std::string& event_name, | 179 void ExtensionMessageService::RemoveEventListener(const std::string& event_name, |
| 171 int render_process_id) { | 180 int render_process_id) { |
| 172 // The RenderProcessHost may be destroyed. See AddEventListener. | 181 // The RenderProcessHost may be destroyed. See AddEventListener. |
| 173 RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id); | 182 RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id); |
| 174 if (!rph || rph->ListenersIterator().IsAtEnd()) | 183 if (!rph || rph->ListenersIterator().IsAtEnd()) |
| 175 return; | 184 return; |
| 176 | 185 |
| 177 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 178 DCHECK_EQ(listeners_[event_name].count(render_process_id), 1u) | 186 DCHECK_EQ(listeners_[event_name].count(render_process_id), 1u) |
| 179 << " PID=" << render_process_id << " event=" << event_name; | 187 << " PID=" << render_process_id << " event=" << event_name; |
| 180 listeners_[event_name].erase(render_process_id); | 188 listeners_[event_name].erase(render_process_id); |
| 181 | 189 |
| 182 if (extension_devtools_manager_.get()) { | 190 if (extension_devtools_manager_.get()) { |
| 183 extension_devtools_manager_->RemoveEventListener(event_name, | 191 extension_devtools_manager_->RemoveEventListener(event_name, |
| 184 render_process_id); | 192 render_process_id); |
| 185 } | 193 } |
| 186 } | 194 } |
| 187 | 195 |
| 188 bool ExtensionMessageService::HasEventListener( | 196 bool ExtensionMessageService::HasEventListener( |
| 189 const std::string& event_name) { | 197 const std::string& event_name) { |
| 190 return (listeners_.find(event_name) != listeners_.end() && | 198 return (listeners_.find(event_name) != listeners_.end() && |
| 191 !listeners_[event_name].empty()); | 199 !listeners_[event_name].empty()); |
| 192 } | 200 } |
| 193 | 201 |
| 194 void ExtensionMessageService::AllocatePortIdPair(int* port1, int* port2) { | 202 void ExtensionMessageService::OpenChannelToExtension( |
| 195 AutoLock lock(next_port_id_lock_); | |
| 196 | |
| 197 // TODO(mpcomplete): what happens when this wraps? | |
| 198 int port1_id = next_port_id_++; | |
| 199 int port2_id = next_port_id_++; | |
| 200 | |
| 201 DCHECK(IS_OPENER_PORT_ID(port1_id)); | |
| 202 DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id); | |
| 203 DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id); | |
| 204 DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id)); | |
| 205 | |
| 206 int channel_id = GET_CHANNEL_ID(port1_id); | |
| 207 DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id); | |
| 208 DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id); | |
| 209 | |
| 210 *port1 = port1_id; | |
| 211 *port2 = port2_id; | |
| 212 } | |
| 213 | |
| 214 int ExtensionMessageService::OpenChannelToExtension( | |
| 215 int routing_id, const std::string& source_extension_id, | |
| 216 const std::string& target_extension_id, | |
| 217 const std::string& channel_name, ResourceMessageFilter* source) { | |
| 218 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | |
| 219 | |
| 220 // Create a channel ID for both sides of the channel. | |
| 221 int port1_id = -1; | |
| 222 int port2_id = -1; | |
| 223 AllocatePortIdPair(&port1_id, &port2_id); | |
| 224 | |
| 225 // Each side of the port is given his own port ID. When they send messages, | |
| 226 // we convert to the opposite port ID. See PostMessageFromRenderer. | |
| 227 ChromeThread::PostTask( | |
| 228 ChromeThread::UI, FROM_HERE, | |
| 229 NewRunnableMethod( | |
| 230 this, &ExtensionMessageService::OpenChannelToExtensionOnUIThread, | |
| 231 source->id(), routing_id, port2_id, source_extension_id, | |
| 232 target_extension_id, channel_name)); | |
| 233 | |
| 234 return port1_id; | |
| 235 } | |
| 236 | |
| 237 int ExtensionMessageService::OpenChannelToTab(int routing_id, | |
| 238 int tab_id, | |
| 239 const std::string& extension_id, | |
| 240 const std::string& channel_name, | |
| 241 ResourceMessageFilter* source) { | |
| 242 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | |
| 243 | |
| 244 // Create a channel ID for both sides of the channel. | |
| 245 int port1_id = -1; | |
| 246 int port2_id = -1; | |
| 247 AllocatePortIdPair(&port1_id, &port2_id); | |
| 248 | |
| 249 // Each side of the port is given his own port ID. When they send messages, | |
| 250 // we convert to the opposite port ID. See PostMessageFromRenderer. | |
| 251 ChromeThread::PostTask( | |
| 252 ChromeThread::UI, FROM_HERE, | |
| 253 NewRunnableMethod( | |
| 254 this, &ExtensionMessageService::OpenChannelToTabOnUIThread, | |
| 255 source->id(), routing_id, port2_id, tab_id, extension_id, | |
| 256 channel_name)); | |
| 257 | |
| 258 return port1_id; | |
| 259 } | |
| 260 | |
| 261 void ExtensionMessageService::OpenChannelToExtensionOnUIThread( | |
| 262 int source_process_id, int source_routing_id, int receiver_port_id, | 203 int source_process_id, int source_routing_id, int receiver_port_id, |
| 263 const std::string& source_extension_id, | 204 const std::string& source_extension_id, |
| 264 const std::string& target_extension_id, | 205 const std::string& target_extension_id, |
| 265 const std::string& channel_name) { | 206 const std::string& channel_name) { |
| 266 if (!profile_) | 207 if (!profile_) |
| 267 return; | 208 return; |
| 268 | 209 |
| 269 RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); | 210 RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); |
| 270 if (!source) | 211 if (!source) |
| 271 return; | 212 return; |
| 272 | 213 |
| 273 MessagePort receiver( | 214 MessagePort receiver( |
| 274 profile_->GetExtensionProcessManager()->GetExtensionProcess( | 215 profile_->GetExtensionProcessManager()->GetExtensionProcess( |
| 275 target_extension_id), | 216 target_extension_id), |
| 276 MSG_ROUTING_CONTROL); | 217 MSG_ROUTING_CONTROL); |
| 277 receiver.debug_info = 1; | |
| 278 TabContents* source_contents = tab_util::GetTabContentsByID( | 218 TabContents* source_contents = tab_util::GetTabContentsByID( |
| 279 source_process_id, source_routing_id); | 219 source_process_id, source_routing_id); |
| 280 | 220 |
| 281 // Include info about the opener's tab (if it was a tab). | 221 // Include info about the opener's tab (if it was a tab). |
| 282 std::string tab_json = "null"; | 222 std::string tab_json = "null"; |
| 283 if (source_contents) { | 223 if (source_contents) { |
| 284 scoped_ptr<DictionaryValue> tab_value( | 224 scoped_ptr<DictionaryValue> tab_value( |
| 285 ExtensionTabUtil::CreateTabValue(source_contents)); | 225 ExtensionTabUtil::CreateTabValue(source_contents)); |
| 286 base::JSONWriter::Write(tab_value.get(), false, &tab_json); | 226 base::JSONWriter::Write(tab_value.get(), false, &tab_json); |
| 287 } | 227 } |
| 288 | 228 |
| 289 OpenChannelOnUIThreadImpl(source, tab_json, | 229 OpenChannelImpl(source, tab_json, receiver, receiver_port_id, |
| 290 receiver, receiver_port_id, | 230 source_extension_id, target_extension_id, channel_name); |
| 291 source_extension_id, target_extension_id, | |
| 292 channel_name); | |
| 293 } | 231 } |
| 294 | 232 |
| 295 void ExtensionMessageService::OpenChannelToTabOnUIThread( | 233 void ExtensionMessageService::OpenChannelToTab( |
| 296 int source_process_id, int source_routing_id, int receiver_port_id, | 234 int source_process_id, int source_routing_id, int receiver_port_id, |
| 297 int tab_id, const std::string& extension_id, | 235 int tab_id, const std::string& extension_id, |
| 298 const std::string& channel_name) { | 236 const std::string& channel_name) { |
| 299 RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); | 237 RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); |
| 300 if (!source) | 238 if (!source) |
| 301 return; | 239 return; |
| 302 | 240 |
| 303 TabContents* contents = NULL; | 241 TabContents* contents = NULL; |
| 304 MessagePort receiver; | 242 MessagePort receiver; |
| 305 receiver.debug_info = 2; | |
| 306 if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), true, | 243 if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), true, |
| 307 NULL, NULL, &contents, NULL)) { | 244 NULL, NULL, &contents, NULL)) { |
| 308 receiver.sender = contents->render_view_host(); | 245 receiver.sender = contents->render_view_host(); |
| 309 receiver.routing_id = contents->render_view_host()->routing_id(); | 246 receiver.routing_id = contents->render_view_host()->routing_id(); |
| 310 receiver.debug_info = 3; | |
| 311 } | 247 } |
| 312 | 248 |
| 313 if (contents && contents->controller().needs_reload()) { | 249 if (contents && contents->controller().needs_reload()) { |
| 314 // The tab isn't loaded yet (it may be phantom). Don't attempt to connect. | 250 // The tab isn't loaded yet (it may be phantom). Don't attempt to connect. |
| 315 // Treat this as a disconnect. | 251 // Treat this as a disconnect. |
| 316 DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL), | 252 DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL), |
| 317 GET_OPPOSITE_PORT_ID(receiver_port_id)); | 253 GET_OPPOSITE_PORT_ID(receiver_port_id)); |
| 318 return; | 254 return; |
| 319 } | 255 } |
| 320 | 256 |
| 321 TabContents* source_contents = tab_util::GetTabContentsByID( | 257 TabContents* source_contents = tab_util::GetTabContentsByID( |
| 322 source_process_id, source_routing_id); | 258 source_process_id, source_routing_id); |
| 323 | 259 |
| 324 // Include info about the opener's tab (if it was a tab). | 260 // Include info about the opener's tab (if it was a tab). |
| 325 std::string tab_json = "null"; | 261 std::string tab_json = "null"; |
| 326 if (source_contents) { | 262 if (source_contents) { |
| 327 scoped_ptr<DictionaryValue> tab_value( | 263 scoped_ptr<DictionaryValue> tab_value( |
| 328 ExtensionTabUtil::CreateTabValue(source_contents)); | 264 ExtensionTabUtil::CreateTabValue(source_contents)); |
| 329 base::JSONWriter::Write(tab_value.get(), false, &tab_json); | 265 base::JSONWriter::Write(tab_value.get(), false, &tab_json); |
| 330 } | 266 } |
| 331 | 267 |
| 332 OpenChannelOnUIThreadImpl(source, tab_json, | 268 OpenChannelImpl(source, tab_json, receiver, receiver_port_id, |
| 333 receiver, receiver_port_id, | 269 extension_id, extension_id, channel_name); |
| 334 extension_id, extension_id, channel_name); | |
| 335 } | 270 } |
| 336 | 271 |
| 337 bool ExtensionMessageService::OpenChannelOnUIThreadImpl( | 272 bool ExtensionMessageService::OpenChannelImpl( |
| 338 IPC::Message::Sender* source, | 273 IPC::Message::Sender* source, |
| 339 const std::string& tab_json, | 274 const std::string& tab_json, |
| 340 const MessagePort& receiver, int receiver_port_id, | 275 const MessagePort& receiver, int receiver_port_id, |
| 341 const std::string& source_extension_id, | 276 const std::string& source_extension_id, |
| 342 const std::string& target_extension_id, | 277 const std::string& target_extension_id, |
| 343 const std::string& channel_name) { | 278 const std::string& channel_name) { |
| 344 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 345 | |
| 346 // TODO(mpcomplete): notify source if receiver doesn't exist | 279 // TODO(mpcomplete): notify source if receiver doesn't exist |
| 347 if (!source) | 280 if (!source) |
| 348 return false; // Closed while in flight. | 281 return false; // Closed while in flight. |
| 349 | 282 |
| 350 if (!receiver.sender) { | 283 if (!receiver.sender) { |
| 351 // Treat it as a disconnect. | 284 // Treat it as a disconnect. |
| 352 DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL), | 285 DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL), |
| 353 GET_OPPOSITE_PORT_ID(receiver_port_id)); | 286 GET_OPPOSITE_PORT_ID(receiver_port_id)); |
| 354 return false; | 287 return false; |
| 355 } | 288 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 373 // opener has the opposite port ID). | 306 // opener has the opposite port ID). |
| 374 DispatchOnConnect(receiver, receiver_port_id, channel_name, tab_json, | 307 DispatchOnConnect(receiver, receiver_port_id, channel_name, tab_json, |
| 375 source_extension_id, target_extension_id); | 308 source_extension_id, target_extension_id); |
| 376 | 309 |
| 377 return true; | 310 return true; |
| 378 } | 311 } |
| 379 | 312 |
| 380 int ExtensionMessageService::OpenSpecialChannelToExtension( | 313 int ExtensionMessageService::OpenSpecialChannelToExtension( |
| 381 const std::string& extension_id, const std::string& channel_name, | 314 const std::string& extension_id, const std::string& channel_name, |
| 382 const std::string& tab_json, IPC::Message::Sender* source) { | 315 const std::string& tab_json, IPC::Message::Sender* source) { |
| 383 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 384 DCHECK(profile_); | 316 DCHECK(profile_); |
| 385 | 317 |
| 386 int port1_id = -1; | 318 int port1_id = -1; |
| 387 int port2_id = -1; | 319 int port2_id = -1; |
| 388 // Create a channel ID for both sides of the channel. | 320 // Create a channel ID for both sides of the channel. |
| 389 AllocatePortIdPair(&port1_id, &port2_id); | 321 AllocatePortIdPair(&port1_id, &port2_id); |
| 390 | 322 |
| 391 MessagePort receiver( | 323 MessagePort receiver( |
| 392 profile_->GetExtensionProcessManager()-> | 324 profile_->GetExtensionProcessManager()-> |
| 393 GetExtensionProcess(extension_id), | 325 GetExtensionProcess(extension_id), |
| 394 MSG_ROUTING_CONTROL); | 326 MSG_ROUTING_CONTROL); |
| 395 receiver.debug_info = 4; | 327 if (!OpenChannelImpl(source, tab_json, receiver, port2_id, |
| 396 if (!OpenChannelOnUIThreadImpl( | 328 extension_id, extension_id, channel_name)) |
| 397 source, tab_json, receiver, port2_id, extension_id, extension_id, | |
| 398 channel_name)) | |
| 399 return -1; | 329 return -1; |
| 400 | 330 |
| 401 return port1_id; | 331 return port1_id; |
| 402 } | 332 } |
| 403 | 333 |
| 404 int ExtensionMessageService::OpenSpecialChannelToTab( | 334 int ExtensionMessageService::OpenSpecialChannelToTab( |
| 405 const std::string& extension_id, const std::string& channel_name, | 335 const std::string& extension_id, const std::string& channel_name, |
| 406 TabContents* target_tab_contents, IPC::Message::Sender* source) { | 336 TabContents* target_tab_contents, IPC::Message::Sender* source) { |
| 407 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 408 DCHECK(target_tab_contents); | 337 DCHECK(target_tab_contents); |
| 409 | 338 |
| 410 if (target_tab_contents->controller().needs_reload()) { | 339 if (target_tab_contents->controller().needs_reload()) { |
| 411 // The tab isn't loaded yet (it may be phantom). Don't attempt to connect. | 340 // The tab isn't loaded yet (it may be phantom). Don't attempt to connect. |
| 412 return -1; | 341 return -1; |
| 413 } | 342 } |
| 414 | 343 |
| 415 int port1_id = -1; | 344 int port1_id = -1; |
| 416 int port2_id = -1; | 345 int port2_id = -1; |
| 417 // Create a channel ID for both sides of the channel. | 346 // Create a channel ID for both sides of the channel. |
| 418 AllocatePortIdPair(&port1_id, &port2_id); | 347 AllocatePortIdPair(&port1_id, &port2_id); |
| 419 | 348 |
| 420 MessagePort receiver( | 349 MessagePort receiver( |
| 421 target_tab_contents->render_view_host(), | 350 target_tab_contents->render_view_host(), |
| 422 target_tab_contents->render_view_host()->routing_id()); | 351 target_tab_contents->render_view_host()->routing_id()); |
| 423 receiver.debug_info = 5; | 352 if (!OpenChannelImpl(source, "null", receiver, port2_id, |
| 424 if (!OpenChannelOnUIThreadImpl(source, "null", | 353 extension_id, extension_id, channel_name)) |
| 425 receiver, port2_id, | |
| 426 extension_id, extension_id, channel_name)) | |
| 427 return -1; | 354 return -1; |
| 428 | 355 |
| 429 return port1_id; | 356 return port1_id; |
| 430 } | 357 } |
| 431 | 358 |
| 432 void ExtensionMessageService::CloseChannel(int port_id) { | 359 void ExtensionMessageService::CloseChannel(int port_id) { |
| 433 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 434 | |
| 435 // Note: The channel might be gone already, if the other side closed first. | 360 // Note: The channel might be gone already, if the other side closed first. |
| 436 MessageChannelMap::iterator it = channels_.find(GET_CHANNEL_ID(port_id)); | 361 MessageChannelMap::iterator it = channels_.find(GET_CHANNEL_ID(port_id)); |
| 437 if (it != channels_.end()) | 362 if (it != channels_.end()) |
| 438 CloseChannelImpl(it, port_id, true); | 363 CloseChannelImpl(it, port_id, true); |
| 439 } | 364 } |
| 440 | 365 |
| 441 void ExtensionMessageService::CloseChannelImpl( | 366 void ExtensionMessageService::CloseChannelImpl( |
| 442 MessageChannelMap::iterator channel_iter, int closing_port_id, | 367 MessageChannelMap::iterator channel_iter, int closing_port_id, |
| 443 bool notify_other_port) { | 368 bool notify_other_port) { |
| 444 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 445 | |
| 446 // Notify the other side. | 369 // Notify the other side. |
| 447 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? | 370 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? |
| 448 channel_iter->second->receiver : channel_iter->second->opener; | 371 channel_iter->second->receiver : channel_iter->second->opener; |
| 449 | 372 |
| 450 if (notify_other_port) | 373 if (notify_other_port) |
| 451 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id)); | 374 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id)); |
| 452 delete channel_iter->second; | 375 delete channel_iter->second; |
| 453 channels_.erase(channel_iter); | 376 channels_.erase(channel_iter); |
| 454 } | 377 } |
| 455 | 378 |
| 456 void ExtensionMessageService::PostMessageFromRenderer( | 379 void ExtensionMessageService::PostMessageFromRenderer( |
| 457 int source_port_id, const std::string& message) { | 380 int source_port_id, const std::string& message) { |
| 458 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 459 | |
| 460 MessageChannelMap::iterator iter = | 381 MessageChannelMap::iterator iter = |
| 461 channels_.find(GET_CHANNEL_ID(source_port_id)); | 382 channels_.find(GET_CHANNEL_ID(source_port_id)); |
| 462 if (iter == channels_.end()) | 383 if (iter == channels_.end()) |
| 463 return; | 384 return; |
| 464 | 385 |
| 465 // Figure out which port the ID corresponds to. | 386 // Figure out which port the ID corresponds to. |
| 466 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); | 387 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); |
| 467 const MessagePort& port = IS_OPENER_PORT_ID(dest_port_id) ? | 388 const MessagePort& port = IS_OPENER_PORT_ID(dest_port_id) ? |
| 468 iter->second->opener : iter->second->receiver; | 389 iter->second->opener : iter->second->receiver; |
| 469 | 390 |
| 470 DispatchOnMessage(port, message, dest_port_id); | 391 DispatchOnMessage(port, message, dest_port_id); |
| 471 } | 392 } |
| 472 | 393 |
| 473 void ExtensionMessageService::DispatchEventToRenderers( | 394 void ExtensionMessageService::DispatchEventToRenderers( |
| 474 const std::string& event_name, const std::string& event_args, | 395 const std::string& event_name, const std::string& event_args, |
| 475 bool has_incognito_data, const GURL& event_url) { | 396 bool has_incognito_data, const GURL& event_url) { |
| 476 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 477 ListenerMap::iterator it = listeners_.find(event_name); | 397 ListenerMap::iterator it = listeners_.find(event_name); |
| 478 if (it == listeners_.end()) | 398 if (it == listeners_.end()) |
| 479 return; | 399 return; |
| 480 | 400 |
| 481 std::set<int>& pids = it->second; | 401 std::set<int>& pids = it->second; |
| 482 | 402 |
| 483 // Send the event only to renderers that are listening for it. | 403 // Send the event only to renderers that are listening for it. |
| 484 for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) { | 404 for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) { |
| 485 RenderProcessHost* renderer = RenderProcessHost::FromID(*pid); | 405 RenderProcessHost* renderer = RenderProcessHost::FromID(*pid); |
| 486 if (!renderer) | 406 if (!renderer) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 500 const std::string& extension_id, | 420 const std::string& extension_id, |
| 501 const std::string& event_name, const std::string& event_args, | 421 const std::string& event_name, const std::string& event_args, |
| 502 bool has_incognito_data, const GURL& event_url) { | 422 bool has_incognito_data, const GURL& event_url) { |
| 503 DispatchEventToRenderers(GetPerExtensionEventName(event_name, extension_id), | 423 DispatchEventToRenderers(GetPerExtensionEventName(event_name, extension_id), |
| 504 event_args, has_incognito_data, event_url); | 424 event_args, has_incognito_data, event_url); |
| 505 } | 425 } |
| 506 | 426 |
| 507 void ExtensionMessageService::Observe(NotificationType type, | 427 void ExtensionMessageService::Observe(NotificationType type, |
| 508 const NotificationSource& source, | 428 const NotificationSource& source, |
| 509 const NotificationDetails& details) { | 429 const NotificationDetails& details) { |
| 510 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
| 511 | |
| 512 switch (type.value) { | 430 switch (type.value) { |
| 513 case NotificationType::RENDERER_PROCESS_TERMINATED: | 431 case NotificationType::RENDERER_PROCESS_TERMINATED: |
| 514 case NotificationType::RENDERER_PROCESS_CLOSED: { | 432 case NotificationType::RENDERER_PROCESS_CLOSED: { |
| 515 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); | 433 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); |
| 516 OnSenderClosed(renderer); | 434 OnSenderClosed(renderer); |
| 517 | 435 |
| 518 // Remove all event listeners associated with this renderer | 436 // Remove all event listeners associated with this renderer |
| 519 for (ListenerMap::iterator it = listeners_.begin(); | 437 for (ListenerMap::iterator it = listeners_.begin(); |
| 520 it != listeners_.end(); ) { | 438 it != listeners_.end(); ) { |
| 521 ListenerMap::iterator current = it++; | 439 ListenerMap::iterator current = it++; |
| 522 if (current->second.count(renderer->id()) != 0) | 440 if (current->second.count(renderer->id()) != 0) |
| 523 RemoveEventListener(current->first, renderer->id()); | 441 RemoveEventListener(current->first, renderer->id()); |
| 524 } | 442 } |
| 525 break; | 443 break; |
| 526 } | 444 } |
| 527 case NotificationType::RENDER_VIEW_HOST_DELETED: | 445 case NotificationType::RENDER_VIEW_HOST_DELETED: |
| 528 OnSenderClosed(Details<RenderViewHost>(details).ptr()); | 446 OnSenderClosed(Details<RenderViewHost>(details).ptr()); |
| 529 break; | 447 break; |
| 530 | |
| 531 // We should already have removed this guy from our channel map by this | |
| 532 // point. | |
| 533 case NotificationType::EXTENSION_PORT_DELETED_DEBUG: { | |
| 534 IPC::Message::Sender* sender = | |
| 535 Details<IPC::Message::Sender>(details).ptr(); | |
| 536 for (MessageChannelMap::iterator it = channels_.begin(); | |
| 537 it != channels_.end(); ) { | |
| 538 MessageChannelMap::iterator current = it++; | |
| 539 int debug_info = current->second->receiver.debug_info; | |
| 540 if (current->second->opener.sender == sender) { | |
| 541 LOG(FATAL) << "Shouldn't happen:" << debug_info; | |
| 542 } else if (current->second->receiver.sender == sender) { | |
| 543 LOG(FATAL) << "Shouldn't happen either: " << debug_info; | |
| 544 } | |
| 545 } | |
| 546 OnSenderClosed(sender); | |
| 547 break; | |
| 548 } | |
| 549 | |
| 550 default: | 448 default: |
| 551 NOTREACHED(); | 449 NOTREACHED(); |
| 552 return; | 450 return; |
| 553 } | 451 } |
| 554 } | 452 } |
| 555 | 453 |
| 556 void ExtensionMessageService::OnSenderClosed(IPC::Message::Sender* sender) { | 454 void ExtensionMessageService::OnSenderClosed(IPC::Message::Sender* sender) { |
| 557 // Close any channels that share this renderer. We notify the opposite | 455 // Close any channels that share this renderer. We notify the opposite |
| 558 // port that his pair has closed. | 456 // port that his pair has closed. |
| 559 for (MessageChannelMap::iterator it = channels_.begin(); | 457 for (MessageChannelMap::iterator it = channels_.begin(); |
| 560 it != channels_.end(); ) { | 458 it != channels_.end(); ) { |
| 561 MessageChannelMap::iterator current = it++; | 459 MessageChannelMap::iterator current = it++; |
| 562 // If both sides are the same renderer, and it is closing, there is no | 460 // If both sides are the same renderer, and it is closing, there is no |
| 563 // "other" port, so there's no need to notify it. | 461 // "other" port, so there's no need to notify it. |
| 564 int debug_info = current->second->receiver.debug_info; | |
| 565 bool debug_check = debug_info == 4 || debug_info == 5; | |
| 566 bool notify_other_port = | 462 bool notify_other_port = |
| 567 current->second->opener.sender != current->second->receiver.sender || | 463 current->second->opener.sender != current->second->receiver.sender; |
| 568 debug_check; | |
| 569 | 464 |
| 570 if (current->second->opener.sender == sender) { | 465 if (current->second->opener.sender == sender) { |
| 571 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first), | 466 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first), |
| 572 notify_other_port); | 467 notify_other_port); |
| 573 } else if (current->second->receiver.sender == sender) { | 468 } else if (current->second->receiver.sender == sender) { |
| 574 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first), | 469 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first), |
| 575 notify_other_port); | 470 notify_other_port); |
| 576 } | 471 } |
| 577 } | 472 } |
| 578 } | 473 } |
| OLD | NEW |