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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/messaging/message_service.h"
7 #include "base/atomic_sequence_num.h"
9 #include "base/callback.h"
10 #include "base/json/json_writer.h"
11 #include "base/lazy_instance.h"
12 #include "base/metrics/histogram.h"
13 #include "base/stl_util.h"
14 #include "base/values.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/api/messaging/extension_message_port.h"
17 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
18 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
19 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_tab_util.h"
22 #include "chrome/browser/extensions/extension_util.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/tab_contents/tab_util.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "content/public/browser/render_widget_host.h"
29 #include "content/public/browser/render_widget_host_view.h"
30 #include "content/public/browser/site_instance.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/extension_host.h"
33 #include "extensions/browser/extension_system.h"
34 #include "extensions/browser/extension_util.h"
35 #include "extensions/browser/extensions_browser_client.h"
36 #include "extensions/browser/lazy_background_task_queue.h"
37 #include "extensions/browser/process_manager.h"
38 #include "extensions/common/extension.h"
39 #include "extensions/common/extension_messages.h"
40 #include "extensions/common/manifest_constants.h"
41 #include "extensions/common/manifest_handlers/background_info.h"
42 #include "extensions/common/manifest_handlers/externally_connectable.h"
43 #include "extensions/common/manifest_handlers/incognito_info.h"
44 #include "extensions/common/permissions/permissions_data.h"
45 #include "net/base/completion_callback.h"
48 using content::BrowserContext
;
49 using content::SiteInstance
;
50 using content::WebContents
;
52 // Since we have 2 ports for every channel, we just index channels by half the
54 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
55 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
56 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
58 // Port1 is always even, port2 is always odd.
59 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
61 // Change even to odd and vice versa, to get the other side of a given channel.
62 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
64 namespace extensions
{
66 const char kReceivingEndDoesntExistError
[] =
67 "Could not establish connection. Receiving end does not exist.";
68 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
69 const char kMissingPermissionError
[] =
70 "Access to native messaging requires nativeMessaging permission.";
71 const char kProhibitedByPoliciesError
[] =
72 "Access to the native messaging host was disabled by the system "
76 struct MessageService::MessageChannel
{
77 scoped_ptr
<MessagePort
> opener
;
78 scoped_ptr
<MessagePort
> receiver
;
81 struct MessageService::OpenChannelParams
{
82 content::RenderProcessHost
* source
;
83 base::DictionaryValue source_tab
;
84 scoped_ptr
<MessagePort
> receiver
;
86 std::string source_extension_id
;
87 std::string target_extension_id
;
89 std::string channel_name
;
90 bool include_tls_channel_id
;
91 std::string tls_channel_id
;
93 // Takes ownership of receiver.
94 OpenChannelParams(content::RenderProcessHost
* source
,
95 scoped_ptr
<base::DictionaryValue
> source_tab
,
96 MessagePort
* receiver
,
98 const std::string
& source_extension_id
,
99 const std::string
& target_extension_id
,
100 const GURL
& source_url
,
101 const std::string
& channel_name
,
102 bool include_tls_channel_id
)
105 receiver_port_id(receiver_port_id
),
106 source_extension_id(source_extension_id
),
107 target_extension_id(target_extension_id
),
108 source_url(source_url
),
109 channel_name(channel_name
),
110 include_tls_channel_id(include_tls_channel_id
) {
112 this->source_tab
.Swap(source_tab
.get());
116 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams
);
121 static base::StaticAtomicSequenceNumber g_next_channel_id
;
122 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count
;
124 static content::RenderProcessHost
* GetExtensionProcess(
125 BrowserContext
* context
,
126 const std::string
& extension_id
) {
127 SiteInstance
* site_instance
=
128 ExtensionSystem::Get(context
)->process_manager()->GetSiteInstanceForURL(
129 Extension::GetBaseURLFromExtensionId(extension_id
));
130 return site_instance
->HasProcess() ? site_instance
->GetProcess() : NULL
;
135 content::RenderProcessHost
*
136 MessageService::MessagePort::GetRenderProcessHost() {
141 void MessageService::AllocatePortIdPair(int* port1
, int* port2
) {
142 unsigned channel_id
=
143 static_cast<unsigned>(g_next_channel_id
.GetNext()) % (kint32max
/2);
145 if (channel_id
== 0) {
146 int overflow_count
= g_channel_id_overflow_count
.GetNext();
147 if (overflow_count
> 0)
148 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
151 unsigned port1_id
= channel_id
* 2;
152 unsigned port2_id
= channel_id
* 2 + 1;
154 // Sanity checks to make sure our channel<->port converters are correct.
155 DCHECK(IS_OPENER_PORT_ID(port1_id
));
156 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id
), port2_id
);
157 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id
), port1_id
);
158 DCHECK_EQ(GET_CHANNEL_ID(port1_id
), GET_CHANNEL_ID(port2_id
));
159 DCHECK_EQ(GET_CHANNEL_ID(port1_id
), channel_id
);
160 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id
), port1_id
);
161 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id
), port2_id
);
167 MessageService::MessageService(BrowserContext
* context
)
168 : lazy_background_task_queue_(
169 ExtensionSystem::Get(context
)->lazy_background_task_queue()),
170 weak_factory_(this) {
171 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
172 content::NotificationService::AllBrowserContextsAndSources());
173 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
174 content::NotificationService::AllBrowserContextsAndSources());
177 MessageService::~MessageService() {
178 STLDeleteContainerPairSecondPointers(channels_
.begin(), channels_
.end());
182 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<MessageService
> >
183 g_factory
= LAZY_INSTANCE_INITIALIZER
;
186 BrowserContextKeyedAPIFactory
<MessageService
>*
187 MessageService::GetFactoryInstance() {
188 return g_factory
.Pointer();
192 MessageService
* MessageService::Get(BrowserContext
* context
) {
193 return BrowserContextKeyedAPIFactory
<MessageService
>::Get(context
);
196 void MessageService::OpenChannelToExtension(
197 int source_process_id
, int source_routing_id
, int receiver_port_id
,
198 const std::string
& source_extension_id
,
199 const std::string
& target_extension_id
,
200 const GURL
& source_url
,
201 const std::string
& channel_name
,
202 bool include_tls_channel_id
) {
203 content::RenderProcessHost
* source
=
204 content::RenderProcessHost::FromID(source_process_id
);
207 BrowserContext
* context
= source
->GetBrowserContext();
209 ExtensionSystem
* extension_system
= ExtensionSystem::Get(context
);
210 DCHECK(extension_system
);
211 const Extension
* target_extension
= extension_system
->extension_service()->
212 extensions()->GetByID(target_extension_id
);
213 if (!target_extension
) {
214 DispatchOnDisconnect(
215 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
219 // Only running ephemeral apps can receive messages. Idle cached ephemeral
220 // apps are invisible and should not be connectable.
221 if (util::IsEphemeralApp(target_extension_id
, context
) &&
222 util::IsExtensionIdle(target_extension_id
, context
)) {
223 DispatchOnDisconnect(
224 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
228 bool is_web_connection
= false;
230 if (source_extension_id
!= target_extension_id
) {
231 // It's an external connection. Check the externally_connectable manifest
232 // key if it's present. If it's not, we allow connection from any extension
234 ExternallyConnectableInfo
* externally_connectable
=
235 static_cast<ExternallyConnectableInfo
*>(
236 target_extension
->GetManifestData(
237 manifest_keys::kExternallyConnectable
));
238 bool is_externally_connectable
= false;
240 if (externally_connectable
) {
241 if (source_extension_id
.empty()) {
242 // No source extension ID so the source was a web page. Check that the
244 is_web_connection
= true;
245 is_externally_connectable
=
246 externally_connectable
->matches
.MatchesURL(source_url
);
247 // Only include the TLS channel ID for externally connected web pages.
248 include_tls_channel_id
&=
249 is_externally_connectable
&&
250 externally_connectable
->accepts_tls_channel_id
;
252 // Source extension ID so the source was an extension. Check that the
253 // extension matches.
254 is_externally_connectable
=
255 externally_connectable
->IdCanConnect(source_extension_id
);
258 // Default behaviour. Any extension, no webpages.
259 is_externally_connectable
= !source_extension_id
.empty();
262 if (!is_externally_connectable
) {
263 // Important: use kReceivingEndDoesntExistError here so that we don't
264 // leak information about this extension to callers. This way it's
265 // indistinguishable from the extension just not existing.
266 DispatchOnDisconnect(
267 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
272 WebContents
* source_contents
= tab_util::GetWebContentsByID(
273 source_process_id
, source_routing_id
);
275 if (context
->IsOffTheRecord() &&
276 !util::IsIncognitoEnabled(target_extension_id
, context
)) {
277 // Give the user a chance to accept an incognito connection from the web if
278 // they haven't already, with the conditions:
279 // - Only for spanning-mode incognito. We don't want the complication of
280 // spinning up an additional process here which might need to do some
281 // setup that we're not expecting.
282 // - Only for extensions that can't normally be enabled in incognito, since
283 // that surface (e.g. chrome://extensions) should be the only one for
284 // enabling in incognito. In practice this means platform apps only.
285 if (!is_web_connection
|| IncognitoInfo::IsSplitMode(target_extension
) ||
286 target_extension
->can_be_incognito_enabled() ||
287 // This check may show a dialog.
288 !IncognitoConnectability::Get(context
)
289 ->Query(target_extension
, source_contents
, source_url
)) {
290 DispatchOnDisconnect(
291 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
296 // Note: we use the source's profile here. If the source is an incognito
297 // process, we will use the incognito EPM to find the right extension process,
298 // which depends on whether the extension uses spanning or split mode.
299 MessagePort
* receiver
= new ExtensionMessagePort(
300 GetExtensionProcess(context
, target_extension_id
),
302 target_extension_id
);
304 // Include info about the opener's tab (if it was a tab).
305 scoped_ptr
<base::DictionaryValue
> source_tab
;
306 GURL source_url_for_tab
;
308 if (source_contents
&& ExtensionTabUtil::GetTabId(source_contents
) >= 0) {
309 // Only the tab id is useful to platform apps for internal use. The
310 // unnecessary bits will be stripped out in
311 // MessagingBindings::DispatchOnConnect().
312 source_tab
.reset(ExtensionTabUtil::CreateTabValue(source_contents
));
313 source_url_for_tab
= source_url
;
316 OpenChannelParams
* params
= new OpenChannelParams(source
,
324 include_tls_channel_id
);
326 // If the target requests the TLS channel id, begin the lookup for it.
327 // The target might also be a lazy background page, checked next, but the
328 // loading of lazy background pages continues asynchronously, so enqueue
329 // messages awaiting TLS channel ID first.
330 if (include_tls_channel_id
) {
331 pending_tls_channel_id_channels_
[GET_CHANNEL_ID(params
->receiver_port_id
)]
332 = PendingMessagesQueue();
333 property_provider_
.GetDomainBoundCert(
334 Profile::FromBrowserContext(context
),
336 base::Bind(&MessageService::GotDomainBoundCert
,
337 weak_factory_
.GetWeakPtr(),
338 base::Passed(make_scoped_ptr(params
))));
342 // The target might be a lazy background page. In that case, we have to check
343 // if it is loaded and ready, and if not, queue up the task and load the
345 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
346 context
, target_extension
, params
)) {
350 OpenChannelImpl(make_scoped_ptr(params
));
353 void MessageService::OpenChannelToNativeApp(
354 int source_process_id
,
355 int source_routing_id
,
356 int receiver_port_id
,
357 const std::string
& source_extension_id
,
358 const std::string
& native_app_name
) {
359 content::RenderProcessHost
* source
=
360 content::RenderProcessHost::FromID(source_process_id
);
364 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
365 Profile
* profile
= Profile::FromBrowserContext(source
->GetBrowserContext());
366 ExtensionService
* extension_service
=
367 ExtensionSystem::Get(profile
)->extension_service();
368 bool has_permission
= false;
369 if (extension_service
) {
370 const Extension
* extension
=
371 extension_service
->GetExtensionById(source_extension_id
, false);
372 has_permission
= extension
&&
373 extension
->permissions_data()->HasAPIPermission(
374 APIPermission::kNativeMessaging
);
377 if (!has_permission
) {
378 DispatchOnDisconnect(source
, receiver_port_id
, kMissingPermissionError
);
382 PrefService
* pref_service
= profile
->GetPrefs();
384 // Verify that the host is not blocked by policies.
385 NativeMessageProcessHost::PolicyPermission policy_permission
=
386 NativeMessageProcessHost::IsHostAllowed(pref_service
, native_app_name
);
387 if (policy_permission
== NativeMessageProcessHost::DISALLOW
) {
388 DispatchOnDisconnect(source
, receiver_port_id
, kProhibitedByPoliciesError
);
392 scoped_ptr
<MessageChannel
> channel(new MessageChannel());
393 channel
->opener
.reset(new ExtensionMessagePort(source
, MSG_ROUTING_CONTROL
,
394 source_extension_id
));
396 // Get handle of the native view and pass it to the native messaging host.
397 gfx::NativeView native_view
=
398 content::RenderWidgetHost::FromID(source_process_id
, source_routing_id
)->
399 GetView()->GetNativeView();
401 scoped_ptr
<NativeMessageProcessHost
> native_process
=
402 NativeMessageProcessHost::Create(
404 base::WeakPtr
<NativeMessageProcessHost::Client
>(
405 weak_factory_
.GetWeakPtr()),
406 source_extension_id
, native_app_name
, receiver_port_id
,
407 policy_permission
== NativeMessageProcessHost::ALLOW_ALL
);
409 // Abandon the channel.
410 if (!native_process
.get()) {
411 LOG(ERROR
) << "Failed to create native process.";
412 DispatchOnDisconnect(
413 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
416 channel
->receiver
.reset(new NativeMessagePort(native_process
.release()));
418 // Keep the opener alive until the channel is closed.
419 channel
->opener
->IncrementLazyKeepaliveCount();
421 AddChannel(channel
.release(), receiver_port_id
);
422 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
423 const char kNativeMessagingNotSupportedError
[] =
424 "Native Messaging is not supported on this platform.";
425 DispatchOnDisconnect(
426 source
, receiver_port_id
, kNativeMessagingNotSupportedError
);
427 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
430 void MessageService::OpenChannelToTab(
431 int source_process_id
, int source_routing_id
, int receiver_port_id
,
432 int tab_id
, const std::string
& extension_id
,
433 const std::string
& channel_name
) {
434 content::RenderProcessHost
* source
=
435 content::RenderProcessHost::FromID(source_process_id
);
438 Profile
* profile
= Profile::FromBrowserContext(source
->GetBrowserContext());
440 WebContents
* contents
= NULL
;
441 scoped_ptr
<MessagePort
> receiver
;
442 if (ExtensionTabUtil::GetTabById(tab_id
, profile
, true,
443 NULL
, NULL
, &contents
, NULL
)) {
444 receiver
.reset(new ExtensionMessagePort(
445 contents
->GetRenderProcessHost(),
446 contents
->GetRenderViewHost()->GetRoutingID(),
450 if (contents
&& contents
->GetController().NeedsReload()) {
451 // The tab isn't loaded yet. Don't attempt to connect.
452 DispatchOnDisconnect(
453 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
457 scoped_ptr
<OpenChannelParams
> params(new OpenChannelParams(
459 scoped_ptr
<base::DictionaryValue
>(), // Source tab doesn't make sense
460 // for opening to tabs.
465 GURL(), // Source URL doesn't make sense for opening to tabs.
467 false)); // Connections to tabs don't get TLS channel IDs.
468 OpenChannelImpl(params
.Pass());
471 bool MessageService::OpenChannelImpl(scoped_ptr
<OpenChannelParams
> params
) {
473 return false; // Closed while in flight.
475 if (!params
->receiver
|| !params
->receiver
->GetRenderProcessHost()) {
476 DispatchOnDisconnect(params
->source
,
477 params
->receiver_port_id
,
478 kReceivingEndDoesntExistError
);
482 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
483 // http://code.google.com/p/chromium/issues/detail?id=19067
484 CHECK(params
->receiver
->GetRenderProcessHost());
486 MessageChannel
* channel(new MessageChannel
);
487 channel
->opener
.reset(new ExtensionMessagePort(params
->source
,
489 params
->source_extension_id
));
490 channel
->receiver
.reset(params
->receiver
.release());
492 CHECK(channel
->receiver
->GetRenderProcessHost());
494 AddChannel(channel
, params
->receiver_port_id
);
496 CHECK(channel
->receiver
->GetRenderProcessHost());
498 // Send the connect event to the receiver. Give it the opener's port ID (the
499 // opener has the opposite port ID).
500 channel
->receiver
->DispatchOnConnect(params
->receiver_port_id
,
501 params
->channel_name
,
503 params
->source_extension_id
,
504 params
->target_extension_id
,
506 params
->tls_channel_id
);
508 // Keep both ends of the channel alive until the channel is closed.
509 channel
->opener
->IncrementLazyKeepaliveCount();
510 channel
->receiver
->IncrementLazyKeepaliveCount();
514 void MessageService::AddChannel(MessageChannel
* channel
, int receiver_port_id
) {
515 int channel_id
= GET_CHANNEL_ID(receiver_port_id
);
516 CHECK(channels_
.find(channel_id
) == channels_
.end());
517 channels_
[channel_id
] = channel
;
518 pending_lazy_background_page_channels_
.erase(channel_id
);
521 void MessageService::CloseChannel(int port_id
,
522 const std::string
& error_message
) {
523 // Note: The channel might be gone already, if the other side closed first.
524 int channel_id
= GET_CHANNEL_ID(port_id
);
525 MessageChannelMap::iterator it
= channels_
.find(channel_id
);
526 if (it
== channels_
.end()) {
527 PendingLazyBackgroundPageChannelMap::iterator pending
=
528 pending_lazy_background_page_channels_
.find(channel_id
);
529 if (pending
!= pending_lazy_background_page_channels_
.end()) {
530 lazy_background_task_queue_
->AddPendingTask(
531 pending
->second
.first
, pending
->second
.second
,
532 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel
,
533 weak_factory_
.GetWeakPtr(), port_id
, error_message
));
537 CloseChannelImpl(it
, port_id
, error_message
, true);
540 void MessageService::CloseChannelImpl(
541 MessageChannelMap::iterator channel_iter
,
543 const std::string
& error_message
,
544 bool notify_other_port
) {
545 MessageChannel
* channel
= channel_iter
->second
;
547 // Notify the other side.
548 if (notify_other_port
) {
549 MessagePort
* port
= IS_OPENER_PORT_ID(closing_port_id
) ?
550 channel
->receiver
.get() : channel
->opener
.get();
551 port
->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id
),
555 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
556 channel
->opener
->DecrementLazyKeepaliveCount();
557 channel
->receiver
->DecrementLazyKeepaliveCount();
559 delete channel_iter
->second
;
560 channels_
.erase(channel_iter
);
563 void MessageService::PostMessage(int source_port_id
, const Message
& message
) {
564 int channel_id
= GET_CHANNEL_ID(source_port_id
);
565 MessageChannelMap::iterator iter
= channels_
.find(channel_id
);
566 if (iter
== channels_
.end()) {
567 // If this channel is pending, queue up the PostMessage to run once
568 // the channel opens.
569 EnqueuePendingMessage(source_port_id
, channel_id
, message
);
573 DispatchMessage(source_port_id
, iter
->second
, message
);
576 void MessageService::PostMessageFromNativeProcess(int port_id
,
577 const std::string
& message
) {
578 PostMessage(port_id
, Message(message
, false /* user_gesture */));
581 void MessageService::Observe(int type
,
582 const content::NotificationSource
& source
,
583 const content::NotificationDetails
& details
) {
585 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
:
586 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
587 content::RenderProcessHost
* renderer
=
588 content::Source
<content::RenderProcessHost
>(source
).ptr();
589 OnProcessClosed(renderer
);
598 void MessageService::OnProcessClosed(content::RenderProcessHost
* process
) {
599 // Close any channels that share this renderer. We notify the opposite
600 // port that his pair has closed.
601 for (MessageChannelMap::iterator it
= channels_
.begin();
602 it
!= channels_
.end(); ) {
603 MessageChannelMap::iterator current
= it
++;
605 content::RenderProcessHost
* opener_process
=
606 current
->second
->opener
->GetRenderProcessHost();
607 content::RenderProcessHost
* receiver_process
=
608 current
->second
->receiver
->GetRenderProcessHost();
610 // Only notify the other side if it has a different porocess host.
611 bool notify_other_port
= opener_process
&& receiver_process
&&
612 opener_process
!= receiver_process
;
614 if (opener_process
== process
) {
615 CloseChannelImpl(current
, GET_CHANNEL_OPENER_ID(current
->first
),
616 std::string(), notify_other_port
);
617 } else if (receiver_process
== process
) {
618 CloseChannelImpl(current
, GET_CHANNEL_RECEIVERS_ID(current
->first
),
619 std::string(), notify_other_port
);
624 void MessageService::EnqueuePendingMessage(int source_port_id
,
626 const Message
& message
) {
627 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id
=
628 pending_tls_channel_id_channels_
.find(channel_id
);
629 if (pending_for_tls_channel_id
!= pending_tls_channel_id_channels_
.end()) {
630 pending_for_tls_channel_id
->second
.push_back(
631 PendingMessage(source_port_id
, message
));
632 // Pending messages must only be pending the TLS channel ID or lazy
633 // background page loading, never both.
636 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id
,
641 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
644 const Message
& message
) {
645 PendingLazyBackgroundPageChannelMap::iterator pending
=
646 pending_lazy_background_page_channels_
.find(channel_id
);
647 if (pending
!= pending_lazy_background_page_channels_
.end()) {
648 lazy_background_task_queue_
->AddPendingTask(
649 pending
->second
.first
, pending
->second
.second
,
650 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage
,
651 weak_factory_
.GetWeakPtr(), source_port_id
, message
));
655 void MessageService::DispatchMessage(int source_port_id
,
656 MessageChannel
* channel
,
657 const Message
& message
) {
658 // Figure out which port the ID corresponds to.
659 int dest_port_id
= GET_OPPOSITE_PORT_ID(source_port_id
);
660 MessagePort
* port
= IS_OPENER_PORT_ID(dest_port_id
) ?
661 channel
->opener
.get() : channel
->receiver
.get();
663 port
->DispatchOnMessage(message
, dest_port_id
);
666 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
667 BrowserContext
* context
,
668 const Extension
* extension
,
669 OpenChannelParams
* params
) {
670 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
673 // If the extension uses spanning incognito mode, make sure we're always
674 // using the original profile since that is what the extension process
676 if (!IncognitoInfo::IsSplitMode(extension
))
677 context
= ExtensionsBrowserClient::Get()->GetOriginalContext(context
);
679 if (!lazy_background_task_queue_
->ShouldEnqueueTask(context
, extension
))
682 pending_lazy_background_page_channels_
683 [GET_CHANNEL_ID(params
->receiver_port_id
)] =
684 PendingLazyBackgroundPageChannel(context
, extension
->id());
685 scoped_ptr
<OpenChannelParams
> scoped_params(params
);
686 lazy_background_task_queue_
->AddPendingTask(
689 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel
,
690 weak_factory_
.GetWeakPtr(),
691 base::Passed(&scoped_params
),
692 params
->source
->GetID()));
696 void MessageService::GotDomainBoundCert(scoped_ptr
<OpenChannelParams
> params
,
697 const std::string
& tls_channel_id
) {
698 params
->tls_channel_id
.assign(tls_channel_id
);
699 int channel_id
= GET_CHANNEL_ID(params
->receiver_port_id
);
701 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id
=
702 pending_tls_channel_id_channels_
.find(channel_id
);
703 if (pending_for_tls_channel_id
== pending_tls_channel_id_channels_
.end()) {
708 BrowserContext
* context
= params
->source
->GetBrowserContext();
710 const Extension
* target_extension
=
711 ExtensionSystem::Get(context
)->extension_service()->extensions()->GetByID(
712 params
->target_extension_id
);
713 if (!target_extension
) {
714 pending_tls_channel_id_channels_
.erase(channel_id
);
715 DispatchOnDisconnect(
716 params
->source
, params
->receiver_port_id
,
717 kReceivingEndDoesntExistError
);
720 PendingMessagesQueue
& pending_messages
= pending_for_tls_channel_id
->second
;
721 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
722 context
, target_extension
, params
.get())) {
723 // Lazy background queue took ownership. Release ours.
724 ignore_result(params
.release());
725 // Messages queued up waiting for the TLS channel ID now need to be queued
726 // up for the lazy background page to load.
727 for (PendingMessagesQueue::iterator it
= pending_messages
.begin();
728 it
!= pending_messages
.end();
730 EnqueuePendingMessageForLazyBackgroundLoad(it
->first
, channel_id
,
734 OpenChannelImpl(params
.Pass());
735 // Messages queued up waiting for the TLS channel ID can be posted now.
736 MessageChannelMap::iterator channel_iter
= channels_
.find(channel_id
);
737 if (channel_iter
!= channels_
.end()) {
738 for (PendingMessagesQueue::iterator it
= pending_messages
.begin();
739 it
!= pending_messages
.end();
741 DispatchMessage(it
->first
, channel_iter
->second
, it
->second
);
745 pending_tls_channel_id_channels_
.erase(channel_id
);
748 void MessageService::PendingLazyBackgroundPageOpenChannel(
749 scoped_ptr
<OpenChannelParams
> params
,
750 int source_process_id
,
751 ExtensionHost
* host
) {
753 return; // TODO(mpcomplete): notify source of disconnect?
755 // Re-lookup the source process since it may no longer be valid.
756 content::RenderProcessHost
* source
=
757 content::RenderProcessHost::FromID(source_process_id
);
761 params
->source
= source
;
762 params
->receiver
.reset(new ExtensionMessagePort(host
->render_process_host(),
764 params
->target_extension_id
));
765 OpenChannelImpl(params
.Pass());
768 void MessageService::DispatchOnDisconnect(content::RenderProcessHost
* source
,
770 const std::string
& error_message
) {
771 ExtensionMessagePort
port(source
, MSG_ROUTING_CONTROL
, "");
772 port
.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id
), error_message
);
775 } // namespace extensions