Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: chrome/browser/extensions/extension_message_service.cc

Issue 155707: Changed the extension.connect() API not to broadcast to all tabs. Added a (Closed)
Patch Set: review comments Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_message_service.h ('k') | chrome/browser/extensions/extension_messages_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698