OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/json_writer.h" | 7 #include "base/json_writer.h" |
8 #include "base/singleton.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" | 12 #include "chrome/browser/chrome_thread.h" |
| 13 #include "chrome/browser/extensions/extension_process_manager.h" |
13 #include "chrome/browser/extensions/extension_tabs_module.h" | 14 #include "chrome/browser/extensions/extension_tabs_module.h" |
| 15 #include "chrome/browser/profile.h" |
14 #include "chrome/browser/renderer_host/render_process_host.h" | 16 #include "chrome/browser/renderer_host/render_process_host.h" |
15 #include "chrome/browser/renderer_host/render_view_host.h" | 17 #include "chrome/browser/renderer_host/render_view_host.h" |
16 #include "chrome/browser/renderer_host/resource_message_filter.h" | 18 #include "chrome/browser/renderer_host/resource_message_filter.h" |
17 #include "chrome/browser/tab_contents/tab_contents.h" | 19 #include "chrome/browser/tab_contents/tab_contents.h" |
18 #include "chrome/browser/tab_contents/tab_util.h" | 20 #include "chrome/browser/tab_contents/tab_util.h" |
19 #include "chrome/common/extensions/extension.h" | 21 #include "chrome/common/extensions/extension.h" |
20 #include "chrome/common/notification_service.h" | 22 #include "chrome/common/notification_service.h" |
21 #include "chrome/common/render_messages.h" | 23 #include "chrome/common/render_messages.h" |
22 | 24 |
23 // Since we have 2 ports for every channel, we just index channels by half the | 25 // Since we have 2 ports for every channel, we just index channels by half the |
24 // port ID. | 26 // port ID. |
25 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) | 27 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) |
26 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) | 28 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) |
27 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) | 29 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) |
28 | 30 |
29 // Port1 is always even, port2 is always odd. | 31 // Port1 is always even, port2 is always odd. |
30 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) | 32 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) |
31 | 33 |
32 // Change even to odd and vice versa, to get the other side of a given channel. | 34 // Change even to odd and vice versa, to get the other side of a given channel. |
33 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) | 35 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) |
34 | 36 |
35 namespace { | 37 struct ExtensionMessageService::MessagePort { |
36 typedef std::map<URLRequestContext*, ExtensionMessageService*> InstanceMap; | 38 IPC::Message::Sender* sender; |
37 struct SingletonData { | 39 int routing_id; |
38 ~SingletonData() { | 40 |
39 STLDeleteContainerPairSecondPointers(map.begin(), map.end()); | 41 MessagePort(IPC::Message::Sender* sender = NULL, |
40 } | 42 int routing_id = MSG_ROUTING_CONTROL) : |
41 Lock lock; | 43 sender(sender), routing_id(routing_id) {} |
42 InstanceMap map; | |
43 }; | 44 }; |
44 | 45 |
45 static void DispatchOnConnect(IPC::Message::Sender* channel, int dest_port_id, | 46 struct ExtensionMessageService::MessageChannel { |
| 47 ExtensionMessageService::MessagePort opener; |
| 48 ExtensionMessageService::MessagePort receiver; |
| 49 }; |
| 50 |
| 51 |
| 52 namespace { |
| 53 |
| 54 static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port, |
| 55 int dest_port_id, |
46 const std::string& channel_name, | 56 const std::string& channel_name, |
47 const std::string& tab_json, | 57 const std::string& tab_json, |
48 const std::string& extension_id) { | 58 const std::string& extension_id) { |
49 ListValue args; | 59 ListValue args; |
50 args.Set(0, Value::CreateIntegerValue(dest_port_id)); | 60 args.Set(0, Value::CreateIntegerValue(dest_port_id)); |
51 args.Set(1, Value::CreateStringValue(channel_name)); | 61 args.Set(1, Value::CreateStringValue(channel_name)); |
52 args.Set(2, Value::CreateStringValue(tab_json)); | 62 args.Set(2, Value::CreateStringValue(tab_json)); |
53 args.Set(3, Value::CreateStringValue(extension_id)); | 63 args.Set(3, Value::CreateStringValue(extension_id)); |
54 channel->Send(new ViewMsg_ExtensionMessageInvoke( | 64 port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
55 ExtensionMessageService::kDispatchOnConnect, args)); | 65 port.routing_id, ExtensionMessageService::kDispatchOnConnect, args)); |
56 } | 66 } |
57 | 67 |
58 static void DispatchOnDisconnect(IPC::Message::Sender* channel, | 68 static void DispatchOnDisconnect( |
59 int source_port_id) { | 69 const ExtensionMessageService::MessagePort& port, int source_port_id) { |
60 ListValue args; | 70 ListValue args; |
61 args.Set(0, Value::CreateIntegerValue(source_port_id)); | 71 args.Set(0, Value::CreateIntegerValue(source_port_id)); |
62 channel->Send(new ViewMsg_ExtensionMessageInvoke( | 72 port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
63 ExtensionMessageService::kDispatchOnDisconnect, args)); | 73 port.routing_id, ExtensionMessageService::kDispatchOnDisconnect, args)); |
64 } | 74 } |
65 | 75 |
66 static void DispatchOnMessage(IPC::Message::Sender* channel, | 76 static void DispatchOnMessage(const ExtensionMessageService::MessagePort& port, |
67 const std::string& message, int source_port_id) { | 77 const std::string& message, int source_port_id) { |
68 ListValue args; | 78 ListValue args; |
69 args.Set(0, Value::CreateStringValue(message)); | 79 args.Set(0, Value::CreateStringValue(message)); |
70 args.Set(1, Value::CreateIntegerValue(source_port_id)); | 80 args.Set(1, Value::CreateIntegerValue(source_port_id)); |
71 channel->Send(new ViewMsg_ExtensionMessageInvoke( | 81 port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
72 ExtensionMessageService::kDispatchOnMessage, args)); | 82 port.routing_id, ExtensionMessageService::kDispatchOnMessage, args)); |
73 } | 83 } |
74 | 84 |
75 static void DispatchEvent(IPC::Message::Sender* channel, | 85 static void DispatchEvent(const ExtensionMessageService::MessagePort& port, |
76 const std::string& event_name, | 86 const std::string& event_name, |
77 const std::string& event_args) { | 87 const std::string& event_args) { |
78 ListValue args; | 88 ListValue args; |
79 args.Set(0, Value::CreateStringValue(event_name)); | 89 args.Set(0, Value::CreateStringValue(event_name)); |
80 args.Set(1, Value::CreateStringValue(event_args)); | 90 args.Set(1, Value::CreateStringValue(event_args)); |
81 channel->Send(new ViewMsg_ExtensionMessageInvoke( | 91 port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
82 ExtensionMessageService::kDispatchEvent, args)); | 92 port.routing_id, ExtensionMessageService::kDispatchEvent, args)); |
83 } | |
84 | |
85 static std::string GetChannelConnectEvent(const std::string& extension_id) { | |
86 return StringPrintf("channel-connect:%s", extension_id.c_str()); | |
87 } | 93 } |
88 | 94 |
89 } // namespace | 95 } // namespace |
90 | 96 |
91 // Since ExtensionMessageService is a collection of Singletons, we don't need to | |
92 // grab a reference to it when creating Tasks involving it. | |
93 template <> struct RunnableMethodTraits<ExtensionMessageService> { | |
94 static void RetainCallee(ExtensionMessageService*) {} | |
95 static void ReleaseCallee(ExtensionMessageService*) {} | |
96 }; | |
97 | |
98 | |
99 const char ExtensionMessageService::kDispatchOnConnect[] = | 97 const char ExtensionMessageService::kDispatchOnConnect[] = |
100 "Port.dispatchOnConnect"; | 98 "Port.dispatchOnConnect"; |
101 const char ExtensionMessageService::kDispatchOnDisconnect[] = | 99 const char ExtensionMessageService::kDispatchOnDisconnect[] = |
102 "Port.dispatchOnDisconnect"; | 100 "Port.dispatchOnDisconnect"; |
103 const char ExtensionMessageService::kDispatchOnMessage[] = | 101 const char ExtensionMessageService::kDispatchOnMessage[] = |
104 "Port.dispatchOnMessage"; | 102 "Port.dispatchOnMessage"; |
105 const char ExtensionMessageService::kDispatchEvent[] = | 103 const char ExtensionMessageService::kDispatchEvent[] = |
106 "Event.dispatchJSON"; | 104 "Event.dispatchJSON"; |
107 | 105 |
108 // static | 106 ExtensionMessageService::ExtensionMessageService(Profile* profile) |
109 ExtensionMessageService* ExtensionMessageService::GetInstance( | 107 : ui_loop_(MessageLoop::current()), profile_(profile), next_port_id_(0) { |
110 URLRequestContext* context) { | 108 DCHECK_EQ(ui_loop_->type(), MessageLoop::TYPE_UI); |
111 SingletonData* data = Singleton<SingletonData>::get(); | |
112 AutoLock lock(data->lock); | |
113 | |
114 ExtensionMessageService* instance = data->map[context]; | |
115 if (!instance) { | |
116 instance = new ExtensionMessageService(); | |
117 data->map[context] = instance; | |
118 } | |
119 return instance; | |
120 } | |
121 | |
122 ExtensionMessageService::ExtensionMessageService() | |
123 : ui_loop_(NULL), initialized_(false), next_port_id_(0) { | |
124 } | |
125 | |
126 void ExtensionMessageService::Init() { | |
127 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
128 | |
129 if (initialized_) | |
130 return; | |
131 initialized_ = true; | |
132 | |
133 ui_loop_ = MessageLoop::current(); | |
134 | 109 |
135 registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED, | 110 registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED, |
136 NotificationService::AllSources()); | 111 NotificationService::AllSources()); |
137 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED, | 112 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED, |
138 NotificationService::AllSources()); | 113 NotificationService::AllSources()); |
| 114 registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, |
| 115 NotificationService::AllSources()); |
| 116 } |
| 117 |
| 118 ExtensionMessageService::~ExtensionMessageService() { |
139 } | 119 } |
140 | 120 |
141 void ExtensionMessageService::AddEventListener(std::string event_name, | 121 void ExtensionMessageService::AddEventListener(std::string event_name, |
142 int render_process_id) { | 122 int render_process_id) { |
143 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 123 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
144 DCHECK(listeners_[event_name].count(render_process_id) == 0); | 124 DCHECK(listeners_[event_name].count(render_process_id) == 0); |
145 listeners_[event_name].insert(render_process_id); | 125 listeners_[event_name].insert(render_process_id); |
146 } | 126 } |
147 | 127 |
148 void ExtensionMessageService::RemoveEventListener(std::string event_name, | 128 void ExtensionMessageService::RemoveEventListener(std::string event_name, |
(...skipping 21 matching lines...) Expand all Loading... |
170 | 150 |
171 *port1 = port1_id; | 151 *port1 = port1_id; |
172 *port2 = port2_id; | 152 *port2 = port2_id; |
173 } | 153 } |
174 | 154 |
175 int ExtensionMessageService::OpenChannelToExtension( | 155 int ExtensionMessageService::OpenChannelToExtension( |
176 int routing_id, const std::string& extension_id, | 156 int routing_id, const std::string& extension_id, |
177 const std::string& channel_name, ResourceMessageFilter* source) { | 157 const std::string& channel_name, ResourceMessageFilter* source) { |
178 DCHECK_EQ(MessageLoop::current(), | 158 DCHECK_EQ(MessageLoop::current(), |
179 ChromeThread::GetMessageLoop(ChromeThread::IO)); | 159 ChromeThread::GetMessageLoop(ChromeThread::IO)); |
180 DCHECK(initialized_); | |
181 | 160 |
182 // Create a channel ID for both sides of the channel. | 161 // Create a channel ID for both sides of the channel. |
183 int port1_id = -1; | 162 int port1_id = -1; |
184 int port2_id = -1; | 163 int port2_id = -1; |
185 AllocatePortIdPair(&port1_id, &port2_id); | 164 AllocatePortIdPair(&port1_id, &port2_id); |
186 | 165 |
187 // Each side of the port is given his own port ID. When they send messages, | 166 // Each side of the port is given his own port ID. When they send messages, |
188 // we convert to the opposite port ID. See PostMessageFromRenderer. | 167 // we convert to the opposite port ID. See PostMessageFromRenderer. |
189 ui_loop_->PostTask(FROM_HERE, | 168 ui_loop_->PostTask(FROM_HERE, |
190 NewRunnableMethod(this, &ExtensionMessageService::OpenChannelOnUIThread, | 169 NewRunnableMethod(this, |
191 routing_id, port2_id, source->GetProcessId(), extension_id, | 170 &ExtensionMessageService::OpenChannelToExtensionOnUIThread, |
| 171 source->GetProcessId(), routing_id, port2_id, extension_id, |
192 channel_name)); | 172 channel_name)); |
193 | 173 |
194 return port1_id; | 174 return port1_id; |
195 } | 175 } |
196 | 176 |
197 void ExtensionMessageService::OpenChannelOnUIThread( | 177 int ExtensionMessageService::OpenChannelToTab( |
198 int source_routing_id, int receivers_port_id, int source_process_id, | 178 int routing_id, int tab_id, const std::string& extension_id, |
| 179 const std::string& channel_name, ResourceMessageFilter* source) { |
| 180 DCHECK_EQ(MessageLoop::current(), |
| 181 ChromeThread::GetMessageLoop(ChromeThread::IO)); |
| 182 |
| 183 // Create a channel ID for both sides of the channel. |
| 184 int port1_id = -1; |
| 185 int port2_id = -1; |
| 186 AllocatePortIdPair(&port1_id, &port2_id); |
| 187 |
| 188 // Each side of the port is given his own port ID. When they send messages, |
| 189 // we convert to the opposite port ID. See PostMessageFromRenderer. |
| 190 ui_loop_->PostTask(FROM_HERE, |
| 191 NewRunnableMethod(this, |
| 192 &ExtensionMessageService::OpenChannelToTabOnUIThread, |
| 193 source->GetProcessId(), routing_id, port2_id, tab_id, extension_id, |
| 194 channel_name)); |
| 195 |
| 196 return port1_id; |
| 197 } |
| 198 |
| 199 void ExtensionMessageService::OpenChannelToExtensionOnUIThread( |
| 200 int source_process_id, int source_routing_id, int receiver_port_id, |
199 const std::string& extension_id, const std::string& channel_name) { | 201 const std::string& extension_id, const std::string& channel_name) { |
| 202 if (!profile_) |
| 203 return; |
| 204 |
200 RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); | 205 RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); |
201 OpenChannelOnUIThreadImpl(source_routing_id, receivers_port_id, | 206 MessagePort receiver( |
202 source_process_id, source, extension_id, | 207 profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id), |
| 208 MSG_ROUTING_CONTROL); |
| 209 OpenChannelOnUIThreadImpl(source, source_process_id, source_routing_id, |
| 210 receiver, receiver_port_id, extension_id, |
| 211 channel_name); |
| 212 } |
| 213 |
| 214 void ExtensionMessageService::OpenChannelToTabOnUIThread( |
| 215 int source_process_id, int source_routing_id, int receiver_port_id, |
| 216 int tab_id, const std::string& extension_id, |
| 217 const std::string& channel_name) { |
| 218 RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); |
| 219 TabContents* contents; |
| 220 MessagePort receiver; |
| 221 if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), |
| 222 NULL, NULL, &contents, NULL)) { |
| 223 receiver.sender = contents->render_view_host(); |
| 224 receiver.routing_id = contents->render_view_host()->routing_id(); |
| 225 } |
| 226 OpenChannelOnUIThreadImpl(source, source_process_id, source_routing_id, |
| 227 receiver, receiver_port_id, extension_id, |
203 channel_name); | 228 channel_name); |
204 } | 229 } |
205 | 230 |
206 void ExtensionMessageService::OpenChannelOnUIThreadImpl( | 231 void ExtensionMessageService::OpenChannelOnUIThreadImpl( |
207 int source_routing_id, int receivers_port_id, int source_process_id, | 232 IPC::Message::Sender* source, int source_process_id, int source_routing_id, |
208 IPC::Message::Sender* source, const std::string& extension_id, | 233 const MessagePort& receiver, int receiver_port_id, |
209 const std::string& channel_name) { | 234 const std::string& extension_id, const std::string& channel_name) { |
210 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 235 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
211 | 236 |
212 if (!source) | 237 // TODO(mpcomplete): notify source if reciever doesn't exist |
213 return; // Source closed while task was in flight. | 238 if (!source || !receiver.sender) |
| 239 return; // Closed while in flight. |
214 | 240 |
215 linked_ptr<MessageChannel> channel(new MessageChannel); | 241 linked_ptr<MessageChannel> channel(new MessageChannel); |
216 channel->opener.insert(source); | 242 channel->opener = MessagePort(source, MSG_ROUTING_CONTROL); |
| 243 channel->receiver = receiver; |
217 | 244 |
218 // Get the list of processes that are listening for this extension's channel | 245 channels_[GET_CHANNEL_ID(receiver_port_id)] = channel; |
219 // connect event. | |
220 std::string event_name = GetChannelConnectEvent(extension_id); | |
221 std::set<int>& pids = listeners_[event_name]; | |
222 for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) { | |
223 RenderProcessHost* renderer = RenderProcessHost::FromID(*pid); | |
224 if (!renderer) | |
225 continue; | |
226 channel->receivers.insert(renderer); | |
227 } | |
228 if (channel->receivers.empty()) { | |
229 // Either no one is listening, or all listeners have since closed. | |
230 // TODO(mpcomplete): should we notify the source? | |
231 return; | |
232 } | |
233 | |
234 channels_[GET_CHANNEL_ID(receivers_port_id)] = channel; | |
235 | 246 |
236 // Include info about the opener's tab (if it was a tab). | 247 // Include info about the opener's tab (if it was a tab). |
237 std::string tab_json = "null"; | 248 std::string tab_json = "null"; |
238 TabContents* contents = tab_util::GetTabContentsByID(source_process_id, | 249 TabContents* contents = tab_util::GetTabContentsByID(source_process_id, |
239 source_routing_id); | 250 source_routing_id); |
240 if (contents) { | 251 if (contents) { |
241 DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(contents); | 252 DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(contents); |
242 JSONWriter::Write(tab_value, false, &tab_json); | 253 JSONWriter::Write(tab_value, false, &tab_json); |
243 } | 254 } |
244 | 255 |
245 // Broadcast the connect event to the receivers. Give them the opener's | 256 // Send the connect event to the receiver. Give it the opener's port ID (the |
246 // port ID (the opener has the opposite port ID). | 257 // opener has the opposite port ID). |
247 for (MessageChannel::Ports::iterator it = channel->receivers.begin(); | 258 DispatchOnConnect(receiver, receiver_port_id, channel_name, tab_json, |
248 it != channel->receivers.end(); ++it) { | 259 extension_id); |
249 DispatchOnConnect(*it, receivers_port_id, channel_name, tab_json, | |
250 extension_id); | |
251 } | |
252 } | 260 } |
253 | 261 |
254 int ExtensionMessageService::OpenAutomationChannelToExtension( | 262 int ExtensionMessageService::OpenAutomationChannelToExtension( |
255 int source_process_id, int routing_id, const std::string& extension_id, | 263 int source_process_id, int routing_id, const std::string& extension_id, |
256 IPC::Message::Sender* source) { | 264 IPC::Message::Sender* source) { |
257 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 265 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
258 DCHECK(initialized_); | 266 DCHECK(profile_); |
259 | 267 |
260 int port1_id = -1; | 268 int port1_id = -1; |
261 int port2_id = -1; | 269 int port2_id = -1; |
262 // Create a channel ID for both sides of the channel. | 270 // Create a channel ID for both sides of the channel. |
263 AllocatePortIdPair(&port1_id, &port2_id); | 271 AllocatePortIdPair(&port1_id, &port2_id); |
264 | 272 |
265 // TODO(siggi): The source process- and routing ids are used to | 273 // TODO(siggi): The source process- and routing ids are used to |
266 // describe the originating tab to the target extension. | 274 // describe the originating tab to the target extension. |
267 // This isn't really appropriate here, the originating tab | 275 // This isn't really appropriate here, the originating tab |
268 // information should be supplied by the caller for | 276 // information should be supplied by the caller for |
269 // automation-initiated ports. | 277 // automation-initiated ports. |
270 OpenChannelOnUIThreadImpl(routing_id, port2_id, source_process_id, | 278 MessagePort receiver( |
271 source, extension_id, ""); | 279 profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id), |
| 280 MSG_ROUTING_CONTROL); |
| 281 OpenChannelOnUIThreadImpl(source, source_process_id, routing_id, receiver, |
| 282 port2_id, extension_id, ""); |
272 | 283 |
273 return port1_id; | 284 return port1_id; |
274 } | 285 } |
275 | 286 |
276 void ExtensionMessageService::CloseChannel(int port_id) { | 287 void ExtensionMessageService::CloseChannel(int port_id) { |
277 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 288 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
278 | 289 |
279 // Note: The channel might be gone already, if the other side closed first. | 290 // Note: The channel might be gone already, if the other side closed first. |
280 MessageChannelMap::iterator it = channels_.find(GET_CHANNEL_ID(port_id)); | 291 MessageChannelMap::iterator it = channels_.find(GET_CHANNEL_ID(port_id)); |
281 if (it != channels_.end()) | 292 if (it != channels_.end()) |
282 CloseChannelImpl(it, port_id); | 293 CloseChannelImpl(it, port_id); |
283 } | 294 } |
284 | 295 |
285 void ExtensionMessageService::CloseChannelImpl( | 296 void ExtensionMessageService::CloseChannelImpl( |
286 MessageChannelMap::iterator channel_iter, int closing_port_id) { | 297 MessageChannelMap::iterator channel_iter, int closing_port_id) { |
287 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 298 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
288 | 299 |
289 // Notify the other side. | 300 // Notify the other side. |
290 MessageChannel::Ports* ports = | 301 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? |
291 IS_OPENER_PORT_ID(closing_port_id) ? | 302 channel_iter->second->receiver : channel_iter->second->opener; |
292 &channel_iter->second->receivers : &channel_iter->second->opener; | |
293 | 303 |
294 for (MessageChannel::Ports::iterator it = ports->begin(); | 304 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id)); |
295 it != ports->end(); ++it) { | |
296 DispatchOnDisconnect(*it, GET_OPPOSITE_PORT_ID(closing_port_id)); | |
297 } | |
298 | |
299 channels_.erase(channel_iter); | 305 channels_.erase(channel_iter); |
300 } | 306 } |
301 | 307 |
302 void ExtensionMessageService::PostMessageFromRenderer( | 308 void ExtensionMessageService::PostMessageFromRenderer( |
303 int source_port_id, const std::string& message) { | 309 int source_port_id, const std::string& message) { |
304 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 310 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
305 | 311 |
306 MessageChannelMap::iterator iter = | 312 MessageChannelMap::iterator iter = |
307 channels_.find(GET_CHANNEL_ID(source_port_id)); | 313 channels_.find(GET_CHANNEL_ID(source_port_id)); |
308 if (iter == channels_.end()) | 314 if (iter == channels_.end()) |
309 return; | 315 return; |
310 | 316 |
311 // Figure out which port the ID corresponds to. | 317 // Figure out which port the ID corresponds to. |
312 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); | 318 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); |
313 MessageChannel::Ports* ports = | 319 const MessagePort& port = IS_OPENER_PORT_ID(dest_port_id) ? |
314 IS_OPENER_PORT_ID(dest_port_id) ? | 320 iter->second->opener : iter->second->receiver; |
315 &iter->second->opener : &iter->second->receivers; | |
316 | 321 |
317 for (MessageChannel::Ports::iterator it = ports->begin(); | 322 DispatchOnMessage(port, message, dest_port_id); |
318 it != ports->end(); ++it) { | |
319 DispatchOnMessage(*it, message, dest_port_id); | |
320 } | |
321 } | 323 } |
322 | 324 |
323 void ExtensionMessageService::DispatchEventToRenderers( | 325 void ExtensionMessageService::DispatchEventToRenderers( |
324 const std::string& event_name, const std::string& event_args) { | 326 const std::string& event_name, const std::string& event_args) { |
325 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 327 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
326 | 328 |
327 std::set<int>& pids = listeners_[event_name]; | 329 std::set<int>& pids = listeners_[event_name]; |
328 | 330 |
329 // Send the event only to renderers that are listening for it. | 331 // Send the event only to renderers that are listening for it. |
330 for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) { | 332 for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) { |
331 RenderProcessHost* renderer = RenderProcessHost::FromID(*pid); | 333 RenderProcessHost* renderer = RenderProcessHost::FromID(*pid); |
332 if (!renderer) | 334 if (!renderer) |
333 continue; | 335 continue; |
334 if (!ChildProcessSecurityPolicy::GetInstance()-> | 336 if (!ChildProcessSecurityPolicy::GetInstance()-> |
335 HasExtensionBindings(*pid)) { | 337 HasExtensionBindings(*pid)) { |
336 // Don't send browser-level events to unprivileged processes. | 338 // Don't send browser-level events to unprivileged processes. |
337 continue; | 339 continue; |
338 } | 340 } |
339 | 341 |
340 DispatchEvent(renderer, event_name, event_args); | 342 DispatchEvent(renderer, event_name, event_args); |
341 } | 343 } |
342 } | 344 } |
343 | 345 |
344 void ExtensionMessageService::Observe(NotificationType type, | 346 void ExtensionMessageService::Observe(NotificationType type, |
345 const NotificationSource& source, | 347 const NotificationSource& source, |
346 const NotificationDetails& details) { | 348 const NotificationDetails& details) { |
347 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | 349 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
348 | 350 |
349 DCHECK(type.value == NotificationType::RENDERER_PROCESS_TERMINATED || | 351 switch (type.value) { |
350 type.value == NotificationType::RENDERER_PROCESS_CLOSED); | 352 case NotificationType::RENDERER_PROCESS_TERMINATED: |
| 353 case NotificationType::RENDERER_PROCESS_CLOSED: { |
| 354 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); |
| 355 OnSenderClosed(renderer); |
351 | 356 |
352 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); | 357 // Remove this renderer from our listener maps. |
| 358 for (ListenerMap::iterator it = listeners_.begin(); |
| 359 it != listeners_.end(); ) { |
| 360 ListenerMap::iterator current = it++; |
| 361 current->second.erase(renderer->pid()); |
| 362 if (current->second.empty()) |
| 363 listeners_.erase(current); |
| 364 } |
| 365 break; |
| 366 } |
| 367 case NotificationType::RENDER_VIEW_HOST_DELETED: |
| 368 OnSenderClosed(Details<RenderViewHost>(details).ptr()); |
| 369 break; |
| 370 default: |
| 371 NOTREACHED(); |
| 372 return; |
| 373 } |
| 374 } |
353 | 375 |
| 376 void ExtensionMessageService::OnSenderClosed(IPC::Message::Sender* sender) { |
354 // Close any channels that share this renderer. We notify the opposite | 377 // Close any channels that share this renderer. We notify the opposite |
355 // port that his pair has closed. | 378 // port that his pair has closed. |
356 for (MessageChannelMap::iterator it = channels_.begin(); | 379 for (MessageChannelMap::iterator it = channels_.begin(); |
357 it != channels_.end(); ) { | 380 it != channels_.end(); ) { |
358 MessageChannelMap::iterator current = it++; | 381 MessageChannelMap::iterator current = it++; |
359 if (current->second->opener.count(renderer) > 0) { | 382 if (current->second->opener.sender == sender) { |
360 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first)); | 383 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first)); |
361 } else if (current->second->receivers.count(renderer) > 0) { | 384 } else if (current->second->receiver.sender == sender) { |
362 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first)); | 385 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first)); |
363 } | 386 } |
364 } | 387 } |
365 | |
366 // Remove this renderer from our listener maps. | |
367 for (ListenerMap::iterator it = listeners_.begin(); | |
368 it != listeners_.end(); ) { | |
369 ListenerMap::iterator current = it++; | |
370 current->second.erase(renderer->pid()); | |
371 if (current->second.empty()) | |
372 listeners_.erase(current); | |
373 } | |
374 } | 388 } |
OLD | NEW |