OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 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/message_service.h" | 5 #include "chrome/browser/extensions/message_service.h" |
6 | 6 |
7 #include "base/atomic_sequence_num.h" | 7 #include "base/atomic_sequence_num.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
12 #include "base/values.h" | 12 #include "base/values.h" |
13 #include "chrome/browser/extensions/extension_host.h" | 13 #include "chrome/browser/extensions/extension_host.h" |
14 #include "chrome/browser/extensions/extension_process_manager.h" | 14 #include "chrome/browser/extensions/extension_process_manager.h" |
15 #include "chrome/browser/extensions/extension_service.h" | 15 #include "chrome/browser/extensions/extension_service.h" |
16 #include "chrome/browser/extensions/extension_system.h" | 16 #include "chrome/browser/extensions/extension_system.h" |
17 #include "chrome/browser/extensions/extension_tab_util.h" | 17 #include "chrome/browser/extensions/extension_tab_util.h" |
18 #include "chrome/browser/extensions/lazy_background_task_queue.h" | 18 #include "chrome/browser/extensions/lazy_background_task_queue.h" |
19 #include "chrome/browser/extensions/native_message_process.h" | |
19 #include "chrome/browser/extensions/process_map.h" | 20 #include "chrome/browser/extensions/process_map.h" |
20 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
21 #include "chrome/browser/tab_contents/tab_util.h" | 22 #include "chrome/browser/tab_contents/tab_util.h" |
22 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 23 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
23 #include "chrome/common/chrome_notification_types.h" | 24 #include "chrome/common/chrome_notification_types.h" |
24 #include "chrome/common/extensions/extension.h" | 25 #include "chrome/common/extensions/extension.h" |
25 #include "chrome/common/extensions/extension_messages.h" | 26 #include "chrome/common/extensions/extension_messages.h" |
26 #include "chrome/common/view_type.h" | 27 #include "chrome/common/view_type.h" |
28 #include "content/public/browser/browser_thread.h" | |
27 #include "content/public/browser/notification_service.h" | 29 #include "content/public/browser/notification_service.h" |
28 #include "content/public/browser/render_process_host.h" | 30 #include "content/public/browser/render_process_host.h" |
29 #include "content/public/browser/render_view_host.h" | 31 #include "content/public/browser/render_view_host.h" |
30 #include "content/public/browser/site_instance.h" | 32 #include "content/public/browser/site_instance.h" |
31 #include "content/public/browser/web_contents.h" | 33 #include "content/public/browser/web_contents.h" |
32 | 34 |
33 using content::SiteInstance; | 35 using content::SiteInstance; |
34 using content::WebContents; | 36 using content::WebContents; |
35 | 37 |
36 // Since we have 2 ports for every channel, we just index channels by half the | 38 // Since we have 2 ports for every channel, we just index channels by half the |
37 // port ID. | 39 // port ID. |
38 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) | 40 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) |
39 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) | 41 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) |
40 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) | 42 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) |
41 | 43 |
42 // Port1 is always even, port2 is always odd. | 44 // Port1 is always even, port2 is always odd. |
43 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) | 45 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) |
44 | 46 |
45 // Change even to odd and vice versa, to get the other side of a given channel. | 47 // Change even to odd and vice versa, to get the other side of a given channel. |
46 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) | 48 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) |
47 | 49 |
48 namespace extensions { | 50 namespace extensions { |
49 | 51 |
50 struct MessageService::MessagePort { | 52 struct MessageService::MessagePort { |
Matt Perry
2012/08/09 02:13:00
maybe we should turn this into an interface that d
Aaron Boodman
2012/08/09 18:36:12
/me is shocked to here mpcomplete say 'interface'.
eaugusti
2012/08/13 23:22:34
Done.
| |
51 content::RenderProcessHost* process; | 53 content::RenderProcessHost* process; |
52 int routing_id; | 54 int routing_id; |
53 std::string extension_id; | 55 std::string extension_id; |
54 void* background_host_ptr; // used in IncrementLazyKeepaliveCount | 56 void* background_host_ptr; // used in IncrementLazyKeepaliveCount |
57 // HACK(eriq) | |
58 bool is_native; | |
59 linked_ptr<NativeMessageProcess> native_process; | |
Aaron Boodman
2012/08/09 18:36:12
linked_ptr here is unfortunate, as it makes the li
eaugusti
2012/08/13 23:22:34
Will now be a raw pointer.
| |
55 | 60 |
56 MessagePort() | 61 MessagePort() |
57 : process(NULL), | 62 : process(NULL), |
58 routing_id(MSG_ROUTING_CONTROL), | 63 routing_id(MSG_ROUTING_CONTROL), |
59 background_host_ptr(NULL) {} | 64 background_host_ptr(NULL), |
65 is_native(false) {} | |
60 MessagePort(content::RenderProcessHost* process, | 66 MessagePort(content::RenderProcessHost* process, |
61 int routing_id, | 67 int routing_id, |
62 const std::string& extension_id) | 68 const std::string& extension_id) |
63 : process(process), | 69 : process(process), |
64 routing_id(routing_id), | 70 routing_id(routing_id), |
65 extension_id(extension_id), | 71 extension_id(extension_id), |
66 background_host_ptr(NULL) {} | 72 background_host_ptr(NULL), |
73 is_native(false) {} | |
67 }; | 74 }; |
68 | 75 |
69 struct MessageService::MessageChannel { | 76 struct MessageService::MessageChannel { |
70 MessageService::MessagePort opener; | 77 MessageService::MessagePort opener; |
71 MessageService::MessagePort receiver; | 78 MessageService::MessagePort receiver; |
72 }; | 79 }; |
73 | 80 |
74 struct MessageService::OpenChannelParams { | 81 struct MessageService::OpenChannelParams { |
75 content::RenderProcessHost* source; | 82 content::RenderProcessHost* source; |
76 std::string tab_json; | 83 std::string tab_json; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
114 static void DispatchOnDisconnect(const MessageService::MessagePort& port, | 121 static void DispatchOnDisconnect(const MessageService::MessagePort& port, |
115 int source_port_id, | 122 int source_port_id, |
116 bool connection_error) { | 123 bool connection_error) { |
117 port.process->Send(new ExtensionMsg_DispatchOnDisconnect( | 124 port.process->Send(new ExtensionMsg_DispatchOnDisconnect( |
118 port.routing_id, source_port_id, connection_error)); | 125 port.routing_id, source_port_id, connection_error)); |
119 } | 126 } |
120 | 127 |
121 static void DispatchOnMessage(const MessageService::MessagePort& port, | 128 static void DispatchOnMessage(const MessageService::MessagePort& port, |
122 const std::string& message, | 129 const std::string& message, |
123 int target_port_id) { | 130 int target_port_id) { |
124 port.process->Send(new ExtensionMsg_DeliverMessage( | 131 if (port.is_native) { |
125 port.routing_id, target_port_id, message)); | 132 port.native_process->Send(message); |
133 } else { | |
134 port.process->Send(new ExtensionMsg_DeliverMessage( | |
135 port.routing_id, target_port_id, message)); | |
136 } | |
126 } | 137 } |
127 | 138 |
128 static content::RenderProcessHost* GetExtensionProcess( | 139 static content::RenderProcessHost* GetExtensionProcess( |
129 Profile* profile, const std::string& extension_id) { | 140 Profile* profile, const std::string& extension_id) { |
130 SiteInstance* site_instance = | 141 SiteInstance* site_instance = |
131 profile->GetExtensionProcessManager()->GetSiteInstanceForURL( | 142 profile->GetExtensionProcessManager()->GetSiteInstanceForURL( |
132 Extension::GetBaseURLFromExtensionId(extension_id)); | 143 Extension::GetBaseURLFromExtensionId(extension_id)); |
133 | 144 |
134 if (!site_instance->HasProcess()) | 145 if (!site_instance->HasProcess()) |
135 return NULL; | 146 return NULL; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
230 | 241 |
231 // The target might be a lazy background page. In that case, we have to check | 242 // The target might be a lazy background page. In that case, we have to check |
232 // if it is loaded and ready, and if not, queue up the task and load the | 243 // if it is loaded and ready, and if not, queue up the task and load the |
233 // page. | 244 // page. |
234 if (MaybeAddPendingOpenChannelTask(profile, params)) | 245 if (MaybeAddPendingOpenChannelTask(profile, params)) |
235 return; | 246 return; |
236 | 247 |
237 OpenChannelImpl(params); | 248 OpenChannelImpl(params); |
238 } | 249 } |
239 | 250 |
251 void MessageService::OpenChannelToNativeApp( | |
252 int source_process_id, | |
253 int source_routing_id, | |
254 int receiver_port_id, | |
255 const std::string& source_extension_id, | |
256 const std::string& native_app_name, | |
257 const std::string& channel_name, | |
258 const std::string& connect_message) { | |
259 content::RenderProcessHost* source = | |
260 content::RenderProcessHost::FromID(source_process_id); | |
261 if (!source) | |
262 return; | |
263 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); | |
264 | |
265 // Note: we use the source's profile here. If the source is an incognito | |
266 // process, we will use the incognito EPM to find the right extension process, | |
267 // which depends on whether the extension uses spanning or split mode. | |
268 MessagePort receiver(GetExtensionProcess(profile, source_extension_id), | |
Matt Perry
2012/08/09 02:13:00
The receiver is the target of the connect event -
eaugusti
2012/08/13 23:22:34
Done.
| |
269 MSG_ROUTING_CONTROL, | |
270 "native"); | |
271 WebContents* source_contents = tab_util::GetWebContentsByID( | |
272 source_process_id, source_routing_id); | |
273 | |
274 // Include info about the opener's tab (if it was a tab). | |
275 std::string tab_json = "null"; | |
276 if (source_contents) { | |
277 scoped_ptr<DictionaryValue> tab_value( | |
278 ExtensionTabUtil::CreateTabValue(source_contents)); | |
279 base::JSONWriter::Write(tab_value.get(), &tab_json); | |
280 } | |
281 | |
282 MessageChannel* channel(new MessageChannel); | |
283 channel->opener = MessagePort(source, MSG_ROUTING_CONTROL, | |
284 source_extension_id); | |
285 channel->receiver = receiver; | |
286 | |
287 content::BrowserThread::PostTask( | |
288 content::BrowserThread::FILE, | |
289 FROM_HERE, | |
290 base::Bind(&MessageService::OpenChannelToNativeAppOnFileThread, | |
291 base::Unretained(this), | |
292 receiver_port_id, | |
293 native_app_name, | |
294 channel_name, | |
295 connect_message, | |
296 channel, | |
297 tab_json)); | |
298 | |
299 // TODO(eriq): This should actually be called after the channel is opened | |
300 // successfully. | |
301 IncrementLazyKeepaliveCount(&channel->opener); | |
302 } | |
303 | |
304 void MessageService::OpenChannelToNativeAppOnFileThread( | |
Matt Perry
2012/08/09 02:13:00
This class is not threadsafe. Same goes for |chann
eaugusti
2012/08/13 23:22:34
Done.
| |
305 int receiver_port_id, | |
306 const std::string& native_app_name, | |
307 const std::string& channel_name, | |
308 const std::string& connect_message, | |
309 MessageChannel* channel, | |
310 const std::string& tab_json) { | |
311 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
312 | |
313 NativeMessageProcess::MessageType type = NativeMessageProcess::TYPE_CONNECT; | |
314 if (channel_name == "chrome.extension.sendNativeMessage") | |
315 type = NativeMessageProcess::TYPE_SEND_MESSAGE_REQUEST; | |
316 | |
317 NativeMessageProcess* native_process = NativeMessageProcess::Create( | |
318 native_app_name, connect_message, this, receiver_port_id, type); | |
Matt Perry
2012/08/09 02:13:00
What if an extension opens 2 channels to the same
Aaron Boodman
2012/08/09 18:36:12
I think we should just create two. The extension s
eaugusti
2012/08/13 23:22:34
I agree with spawning multiple processes, the nati
| |
319 if (!native_process) { | |
320 LOG(ERROR) << "Failed to create native process."; | |
321 return; | |
322 } | |
323 channel->receiver.is_native = true; | |
324 channel->receiver.native_process.reset(native_process); | |
325 | |
326 int channel_id = GET_CHANNEL_ID(receiver_port_id); | |
327 CHECK(channels_.find(channel_id) == channels_.end()); | |
328 channels_[channel_id] = channel; | |
329 pending_channels_.erase(channel_id); | |
330 | |
331 // Send the connect event to the receiver. Give it the opener's port ID (the | |
332 // opener has the opposite port ID). | |
333 DispatchOnConnect(channel->receiver, receiver_port_id, | |
Matt Perry
2012/08/09 02:13:00
I don't think this call makes sense. You're dispat
eaugusti
2012/08/13 23:22:34
You're right, it doesn't make sense.
| |
334 channel_name, tab_json, | |
335 channel->opener.extension_id, "native"); | |
336 } | |
337 | |
240 void MessageService::OpenChannelToTab( | 338 void MessageService::OpenChannelToTab( |
241 int source_process_id, int source_routing_id, int receiver_port_id, | 339 int source_process_id, int source_routing_id, int receiver_port_id, |
242 int tab_id, const std::string& extension_id, | 340 int tab_id, const std::string& extension_id, |
243 const std::string& channel_name) { | 341 const std::string& channel_name) { |
244 content::RenderProcessHost* source = | 342 content::RenderProcessHost* source = |
245 content::RenderProcessHost::FromID(source_process_id); | 343 content::RenderProcessHost::FromID(source_process_id); |
246 if (!source) | 344 if (!source) |
247 return; | 345 return; |
248 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); | 346 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); |
249 | 347 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
341 | 439 |
342 void MessageService::CloseChannelImpl( | 440 void MessageService::CloseChannelImpl( |
343 MessageChannelMap::iterator channel_iter, int closing_port_id, | 441 MessageChannelMap::iterator channel_iter, int closing_port_id, |
344 bool connection_error, bool notify_other_port) { | 442 bool connection_error, bool notify_other_port) { |
345 MessageChannel* channel = channel_iter->second; | 443 MessageChannel* channel = channel_iter->second; |
346 | 444 |
347 // Notify the other side. | 445 // Notify the other side. |
348 if (notify_other_port) { | 446 if (notify_other_port) { |
349 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? | 447 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? |
350 channel->receiver : channel->opener; | 448 channel->receiver : channel->opener; |
351 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), | 449 |
352 connection_error); | 450 if (!port.is_native) { |
451 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), | |
452 connection_error); | |
453 } | |
353 } | 454 } |
354 | 455 |
355 // Balance the addrefs in OpenChannelImpl. | 456 // Balance the addrefs in OpenChannelImpl. |
356 DecrementLazyKeepaliveCount(&channel->opener); | 457 DecrementLazyKeepaliveCount(&channel->opener); |
357 DecrementLazyKeepaliveCount(&channel->receiver); | 458 // The reciever may be native. |
459 if (!channel->receiver.is_native) { | |
460 DecrementLazyKeepaliveCount(&channel->receiver); | |
461 } | |
358 | 462 |
359 delete channel_iter->second; | 463 delete channel_iter->second; |
360 channels_.erase(channel_iter); | 464 channels_.erase(channel_iter); |
361 } | 465 } |
362 | 466 |
363 void MessageService::PostMessageFromRenderer( | 467 void MessageService::PostMessageFromRenderer( |
364 int source_port_id, const std::string& message) { | 468 int source_port_id, const std::string& message) { |
365 int channel_id = GET_CHANNEL_ID(source_port_id); | 469 int channel_id = GET_CHANNEL_ID(source_port_id); |
366 MessageChannelMap::iterator iter = channels_.find(channel_id); | 470 MessageChannelMap::iterator iter = channels_.find(channel_id); |
367 if (iter == channels_.end()) { | 471 if (iter == channels_.end()) { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 if (!params.source) | 566 if (!params.source) |
463 return; | 567 return; |
464 | 568 |
465 params.receiver = MessagePort(host->render_process_host(), | 569 params.receiver = MessagePort(host->render_process_host(), |
466 MSG_ROUTING_CONTROL, | 570 MSG_ROUTING_CONTROL, |
467 params.target_extension_id); | 571 params.target_extension_id); |
468 OpenChannelImpl(params); | 572 OpenChannelImpl(params); |
469 } | 573 } |
470 | 574 |
471 } // namespace extensions | 575 } // namespace extensions |
OLD | NEW |