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/api/messaging/message_service.h" | 5 #include "chrome/browser/extensions/api/messaging/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/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "chrome/browser/chrome_notification_types.h" | 15 #include "chrome/browser/chrome_notification_types.h" |
16 #include "chrome/browser/extensions/api/messaging/extension_message_port.h" | 16 #include "chrome/browser/extensions/api/messaging/extension_message_port.h" |
17 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h" | 17 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h" |
18 #include "chrome/browser/extensions/api/messaging/native_message_port.h" | 18 #include "chrome/browser/extensions/api/messaging/native_message_port.h" |
| 19 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
19 #include "chrome/browser/extensions/extension_host.h" | 20 #include "chrome/browser/extensions/extension_host.h" |
20 #include "chrome/browser/extensions/extension_service.h" | 21 #include "chrome/browser/extensions/extension_service.h" |
21 #include "chrome/browser/extensions/extension_system.h" | 22 #include "chrome/browser/extensions/extension_system.h" |
22 #include "chrome/browser/extensions/extension_tab_util.h" | 23 #include "chrome/browser/extensions/extension_tab_util.h" |
23 #include "chrome/browser/extensions/extension_util.h" | 24 #include "chrome/browser/extensions/extension_util.h" |
24 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
25 #include "chrome/browser/tab_contents/tab_util.h" | 26 #include "chrome/browser/tab_contents/tab_util.h" |
26 #include "chrome/common/extensions/extension_messages.h" | 27 #include "chrome/common/extensions/extension_messages.h" |
27 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" | 28 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" |
28 #include "content/public/browser/notification_service.h" | 29 #include "content/public/browser/notification_service.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 scoped_ptr<MessagePort> receiver; | 74 scoped_ptr<MessagePort> receiver; |
74 }; | 75 }; |
75 | 76 |
76 struct MessageService::OpenChannelParams { | 77 struct MessageService::OpenChannelParams { |
77 content::RenderProcessHost* source; | 78 content::RenderProcessHost* source; |
78 base::DictionaryValue source_tab; | 79 base::DictionaryValue source_tab; |
79 scoped_ptr<MessagePort> receiver; | 80 scoped_ptr<MessagePort> receiver; |
80 int receiver_port_id; | 81 int receiver_port_id; |
81 std::string source_extension_id; | 82 std::string source_extension_id; |
82 std::string target_extension_id; | 83 std::string target_extension_id; |
83 GURL source_url; | |
84 std::string channel_name; | 84 std::string channel_name; |
85 bool include_tls_channel_id; | 85 bool include_tls_channel_id; |
86 std::string tls_channel_id; | 86 std::string tls_channel_id; |
87 | 87 |
88 // Takes ownership of receiver. | 88 // Takes ownership of receiver. |
89 OpenChannelParams(content::RenderProcessHost* source, | 89 OpenChannelParams(content::RenderProcessHost* source, |
90 scoped_ptr<base::DictionaryValue> source_tab, | 90 scoped_ptr<base::DictionaryValue> source_tab, |
91 MessagePort* receiver, | 91 MessagePort* receiver, |
92 int receiver_port_id, | 92 int receiver_port_id, |
93 const std::string& source_extension_id, | 93 const std::string& source_extension_id, |
94 const std::string& target_extension_id, | 94 const std::string& target_extension_id, |
95 const GURL& source_url, | |
96 const std::string& channel_name, | 95 const std::string& channel_name, |
97 bool include_tls_channel_id) | 96 bool include_tls_channel_id) |
98 : source(source), | 97 : source(source), |
99 receiver(receiver), | 98 receiver(receiver), |
100 receiver_port_id(receiver_port_id), | 99 receiver_port_id(receiver_port_id), |
101 source_extension_id(source_extension_id), | 100 source_extension_id(source_extension_id), |
102 target_extension_id(target_extension_id), | 101 target_extension_id(target_extension_id), |
103 source_url(source_url), | |
104 channel_name(channel_name), | 102 channel_name(channel_name), |
105 include_tls_channel_id(include_tls_channel_id) { | 103 include_tls_channel_id(include_tls_channel_id) { |
106 if (source_tab) | 104 if (source_tab) |
107 this->source_tab.Swap(source_tab.get()); | 105 this->source_tab.Swap(source_tab.get()); |
108 } | 106 } |
109 | 107 |
110 private: | 108 private: |
111 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams); | 109 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams); |
112 }; | 110 }; |
113 | 111 |
114 namespace { | 112 namespace { |
115 | 113 |
116 static base::StaticAtomicSequenceNumber g_next_channel_id; | 114 static base::StaticAtomicSequenceNumber g_next_channel_id; |
117 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count; | 115 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count; |
118 | 116 |
119 static content::RenderProcessHost* GetExtensionProcess( | 117 static content::RenderProcessHost* GetExtensionProcess( |
120 Profile* profile, const std::string& extension_id) { | 118 Profile* profile, const std::string& extension_id) { |
121 SiteInstance* site_instance = | 119 SiteInstance* site_instance = |
122 ExtensionSystem::Get(profile)->process_manager()-> | 120 ExtensionSystem::Get(profile)->process_manager()->GetSiteInstanceForURL( |
123 GetSiteInstanceForURL( | 121 Extension::GetBaseURLFromExtensionId(extension_id)); |
124 Extension::GetBaseURLFromExtensionId(extension_id)); | 122 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL; |
125 | |
126 if (!site_instance->HasProcess()) | |
127 return NULL; | |
128 | |
129 return site_instance->GetProcess(); | |
130 } | 123 } |
131 | 124 |
132 } // namespace | 125 } // namespace |
133 | 126 |
134 content::RenderProcessHost* | 127 content::RenderProcessHost* |
135 MessageService::MessagePort::GetRenderProcessHost() { | 128 MessageService::MessagePort::GetRenderProcessHost() { |
136 return NULL; | 129 return NULL; |
137 } | 130 } |
138 | 131 |
139 // static | 132 // static |
140 void MessageService::AllocatePortIdPair(int* port1, int* port2) { | 133 void MessageService::AllocatePortIdPair(int* port1, int* port2) { |
141 unsigned channel_id = | 134 unsigned channel_id = |
142 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2); | 135 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2); |
143 | 136 |
144 if (channel_id == 0) { | 137 if (channel_id == 0) { |
145 int overflow_count = g_channel_id_overflow_count.GetNext(); | 138 int overflow_count = g_channel_id_overflow_count.GetNext(); |
146 if (overflow_count > 0) | 139 if (overflow_count > 0) |
147 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true); | 140 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true); |
148 } | 141 } |
149 | 142 |
150 unsigned port1_id = channel_id * 2; | 143 unsigned port1_id = channel_id * 2; |
151 unsigned port2_id = channel_id * 2 + 1; | 144 unsigned port2_id = channel_id * 2 + 1; |
152 | 145 |
153 // Sanity checks to make sure our channel<->port converters are correct. | 146 // Sanity checks to make sure our channel<->port converters are correct. |
154 DCHECK(IS_OPENER_PORT_ID(port1_id)); | 147 DCHECK(IS_OPENER_PORT_ID(port1_id)); |
155 DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id); | 148 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id); |
156 DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id); | 149 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id); |
157 DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id)); | 150 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id)); |
158 DCHECK(GET_CHANNEL_ID(port1_id) == channel_id); | 151 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id); |
159 DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id); | 152 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id); |
160 DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id); | 153 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id); |
161 | 154 |
162 *port1 = port1_id; | 155 *port1 = port1_id; |
163 *port2 = port2_id; | 156 *port2 = port2_id; |
164 } | 157 } |
165 | 158 |
166 MessageService::MessageService(Profile* profile) | 159 MessageService::MessageService(Profile* profile) |
167 : lazy_background_task_queue_( | 160 : lazy_background_task_queue_( |
168 ExtensionSystem::Get(profile)->lazy_background_task_queue()), | 161 ExtensionSystem::Get(profile)->lazy_background_task_queue()), |
169 weak_factory_(this) { | 162 weak_factory_(this) { |
170 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 163 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 | 285 |
293 // Note: we use the source's profile here. If the source is an incognito | 286 // Note: we use the source's profile here. If the source is an incognito |
294 // process, we will use the incognito EPM to find the right extension process, | 287 // process, we will use the incognito EPM to find the right extension process, |
295 // which depends on whether the extension uses spanning or split mode. | 288 // which depends on whether the extension uses spanning or split mode. |
296 MessagePort* receiver = new ExtensionMessagePort( | 289 MessagePort* receiver = new ExtensionMessagePort( |
297 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL, | 290 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL, |
298 target_extension_id); | 291 target_extension_id); |
299 | 292 |
300 // Include info about the opener's tab (if it was a tab). | 293 // Include info about the opener's tab (if it was a tab). |
301 scoped_ptr<base::DictionaryValue> source_tab; | 294 scoped_ptr<base::DictionaryValue> source_tab; |
302 GURL source_url_for_tab; | |
303 | |
304 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) { | 295 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) { |
305 // Platform apps can be sent messages, but don't have a Tab concept. | 296 // Platform apps can be sent messages, but don't have a Tab concept. |
306 if (!target_extension->is_platform_app()) | 297 // Only the tab id is useful to platform apps for internal use. The |
307 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents)); | 298 // unnecessary bits will be stripped out in |
308 source_url_for_tab = source_url; | 299 // MessagingBindings::DispatchOnConnect(). |
| 300 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents)); |
309 } | 301 } |
310 | 302 |
311 OpenChannelParams* params = new OpenChannelParams(source, | 303 OpenChannelParams* params = new OpenChannelParams(source, |
312 source_tab.Pass(), | 304 source_tab.Pass(), |
313 receiver, | 305 receiver, |
314 receiver_port_id, | 306 receiver_port_id, |
315 source_extension_id, | 307 source_extension_id, |
316 target_extension_id, | 308 target_extension_id, |
317 source_url_for_tab, | |
318 channel_name, | 309 channel_name, |
319 include_tls_channel_id); | 310 include_tls_channel_id); |
320 | 311 |
321 // If the target requests the TLS channel id, begin the lookup for it. | 312 // If the target requests the TLS channel id, begin the lookup for it. |
322 // The target might also be a lazy background page, checked next, but the | 313 // The target might also be a lazy background page, checked next, but the |
323 // loading of lazy background pages continues asynchronously, so enqueue | 314 // loading of lazy background pages continues asynchronously, so enqueue |
324 // messages awaiting TLS channel ID first. | 315 // messages awaiting TLS channel ID first. |
325 if (include_tls_channel_id) { | 316 if (include_tls_channel_id) { |
326 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)] | 317 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)] |
327 = PendingMessagesQueue(); | 318 = PendingMessagesQueue(); |
328 property_provider_.GetDomainBoundCert(profile, params->source_url, | 319 property_provider_.GetDomainBoundCert( |
| 320 profile, |
| 321 source_url, |
329 base::Bind(&MessageService::GotDomainBoundCert, | 322 base::Bind(&MessageService::GotDomainBoundCert, |
330 weak_factory_.GetWeakPtr(), | 323 weak_factory_.GetWeakPtr(), |
331 base::Passed(make_scoped_ptr(params)))); | 324 base::Passed(make_scoped_ptr(params)))); |
332 return; | 325 return; |
333 } | 326 } |
334 | 327 |
335 // The target might be a lazy background page. In that case, we have to check | 328 // The target might be a lazy background page. In that case, we have to check |
336 // if it is loaded and ready, and if not, queue up the task and load the | 329 // if it is loaded and ready, and if not, queue up the task and load the |
337 // page. | 330 // page. |
338 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile, | 331 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile, |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 } | 437 } |
445 | 438 |
446 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( | 439 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( |
447 source, | 440 source, |
448 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense | 441 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense |
449 // for opening to tabs. | 442 // for opening to tabs. |
450 receiver.release(), | 443 receiver.release(), |
451 receiver_port_id, | 444 receiver_port_id, |
452 extension_id, | 445 extension_id, |
453 extension_id, | 446 extension_id, |
454 GURL(), // Source URL doesn't make sense for opening to tabs. | |
455 channel_name, | 447 channel_name, |
456 false)); // Connections to tabs don't get TLS channel IDs. | 448 false)); // Connections to tabs don't get TLS channel IDs. |
457 OpenChannelImpl(params.Pass()); | 449 OpenChannelImpl(params.Pass()); |
458 } | 450 } |
459 | 451 |
460 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { | 452 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { |
461 if (!params->source) | 453 if (!params->source) |
462 return false; // Closed while in flight. | 454 return false; // Closed while in flight. |
463 | 455 |
464 if (!params->receiver || !params->receiver->GetRenderProcessHost()) { | 456 if (!params->receiver || !params->receiver->GetRenderProcessHost()) { |
(...skipping 14 matching lines...) Expand all Loading... |
479 channel->receiver.reset(params->receiver.release()); | 471 channel->receiver.reset(params->receiver.release()); |
480 | 472 |
481 CHECK(channel->receiver->GetRenderProcessHost()); | 473 CHECK(channel->receiver->GetRenderProcessHost()); |
482 | 474 |
483 AddChannel(channel, params->receiver_port_id); | 475 AddChannel(channel, params->receiver_port_id); |
484 | 476 |
485 CHECK(channel->receiver->GetRenderProcessHost()); | 477 CHECK(channel->receiver->GetRenderProcessHost()); |
486 | 478 |
487 // Send the connect event to the receiver. Give it the opener's port ID (the | 479 // Send the connect event to the receiver. Give it the opener's port ID (the |
488 // opener has the opposite port ID). | 480 // opener has the opposite port ID). |
| 481 // TODO(thestig) It is likely possible to get rid of |source_url| here and |
| 482 // pull it out of |params| further down the call path. |
| 483 std::string source_url; |
| 484 params->source_tab.GetString(tabs_constants::kUrlKey, &source_url); |
489 channel->receiver->DispatchOnConnect(params->receiver_port_id, | 485 channel->receiver->DispatchOnConnect(params->receiver_port_id, |
490 params->channel_name, | 486 params->channel_name, |
491 params->source_tab, | 487 params->source_tab, |
492 params->source_extension_id, | 488 params->source_extension_id, |
493 params->target_extension_id, | 489 params->target_extension_id, |
494 params->source_url, | 490 GURL(source_url), |
495 params->tls_channel_id); | 491 params->tls_channel_id); |
496 | 492 |
497 // Keep both ends of the channel alive until the channel is closed. | 493 // Keep both ends of the channel alive until the channel is closed. |
498 channel->opener->IncrementLazyKeepaliveCount(); | 494 channel->opener->IncrementLazyKeepaliveCount(); |
499 channel->receiver->IncrementLazyKeepaliveCount(); | 495 channel->receiver->IncrementLazyKeepaliveCount(); |
500 return true; | 496 return true; |
501 } | 497 } |
502 | 498 |
503 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) { | 499 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) { |
504 int channel_id = GET_CHANNEL_ID(receiver_port_id); | 500 int channel_id = GET_CHANNEL_ID(receiver_port_id); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 } | 538 } |
543 | 539 |
544 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl. | 540 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl. |
545 channel->opener->DecrementLazyKeepaliveCount(); | 541 channel->opener->DecrementLazyKeepaliveCount(); |
546 channel->receiver->DecrementLazyKeepaliveCount(); | 542 channel->receiver->DecrementLazyKeepaliveCount(); |
547 | 543 |
548 delete channel_iter->second; | 544 delete channel_iter->second; |
549 channels_.erase(channel_iter); | 545 channels_.erase(channel_iter); |
550 } | 546 } |
551 | 547 |
552 void MessageService::PostMessage( | 548 void MessageService::PostMessage(int source_port_id, const Message& message) { |
553 int source_port_id, const Message& message) { | |
554 int channel_id = GET_CHANNEL_ID(source_port_id); | 549 int channel_id = GET_CHANNEL_ID(source_port_id); |
555 MessageChannelMap::iterator iter = channels_.find(channel_id); | 550 MessageChannelMap::iterator iter = channels_.find(channel_id); |
556 if (iter == channels_.end()) { | 551 if (iter == channels_.end()) { |
557 // If this channel is pending, queue up the PostMessage to run once | 552 // If this channel is pending, queue up the PostMessage to run once |
558 // the channel opens. | 553 // the channel opens. |
559 EnqueuePendingMessage(source_port_id, channel_id, message); | 554 EnqueuePendingMessage(source_port_id, channel_id, message); |
560 return; | 555 return; |
561 } | 556 } |
562 | 557 |
563 DispatchMessage(source_port_id, iter->second, message); | 558 DispatchMessage(source_port_id, iter->second, message); |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 } | 749 } |
755 | 750 |
756 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, | 751 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, |
757 int port_id, | 752 int port_id, |
758 const std::string& error_message) { | 753 const std::string& error_message) { |
759 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); | 754 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); |
760 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message); | 755 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message); |
761 } | 756 } |
762 | 757 |
763 } // namespace extensions | 758 } // namespace extensions |
OLD | NEW |