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/extensions_browser_client.h"
35 #include "extensions/browser/lazy_background_task_queue.h"
36 #include "extensions/browser/process_manager.h"
37 #include "extensions/common/extension.h"
38 #include "extensions/common/extension_messages.h"
39 #include "extensions/common/manifest_constants.h"
40 #include "extensions/common/manifest_handlers/background_info.h"
41 #include "extensions/common/manifest_handlers/externally_connectable.h"
42 #include "extensions/common/manifest_handlers/incognito_info.h"
43 #include "net/base/completion_callback.h"
46 using content::BrowserContext;
47 using content::SiteInstance;
48 using content::WebContents;
50 // Since we have 2 ports for every channel, we just index channels by half the
52 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
53 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
54 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
56 // Port1 is always even, port2 is always odd.
57 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
59 // Change even to odd and vice versa, to get the other side of a given channel.
60 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
62 namespace extensions {
64 const char kReceivingEndDoesntExistError[] =
65 "Could not establish connection. Receiving end does not exist.";
66 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
67 const char kMissingPermissionError[] =
68 "Access to native messaging requires nativeMessaging permission.";
69 const char kProhibitedByPoliciesError[] =
70 "Access to the native messaging host was disabled by the system "
74 struct MessageService::MessageChannel {
75 scoped_ptr<MessagePort> opener;
76 scoped_ptr<MessagePort> receiver;
79 struct MessageService::OpenChannelParams {
80 content::RenderProcessHost* source;
81 base::DictionaryValue source_tab;
82 scoped_ptr<MessagePort> receiver;
84 std::string source_extension_id;
85 std::string target_extension_id;
87 std::string channel_name;
88 bool include_tls_channel_id;
89 std::string tls_channel_id;
91 // Takes ownership of receiver.
92 OpenChannelParams(content::RenderProcessHost* source,
93 scoped_ptr<base::DictionaryValue> source_tab,
94 MessagePort* receiver,
96 const std::string& source_extension_id,
97 const std::string& target_extension_id,
98 const GURL& source_url,
99 const std::string& channel_name,
100 bool include_tls_channel_id)
103 receiver_port_id(receiver_port_id),
104 source_extension_id(source_extension_id),
105 target_extension_id(target_extension_id),
106 source_url(source_url),
107 channel_name(channel_name),
108 include_tls_channel_id(include_tls_channel_id) {
110 this->source_tab.Swap(source_tab.get());
114 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
119 static base::StaticAtomicSequenceNumber g_next_channel_id;
120 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
122 static content::RenderProcessHost* GetExtensionProcess(
123 BrowserContext* context,
124 const std::string& extension_id) {
125 SiteInstance* site_instance =
126 ExtensionSystem::Get(context)->process_manager()->GetSiteInstanceForURL(
127 Extension::GetBaseURLFromExtensionId(extension_id));
128 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
133 content::RenderProcessHost*
134 MessageService::MessagePort::GetRenderProcessHost() {
139 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
140 unsigned channel_id =
141 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
143 if (channel_id == 0) {
144 int overflow_count = g_channel_id_overflow_count.GetNext();
145 if (overflow_count > 0)
146 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
149 unsigned port1_id = channel_id * 2;
150 unsigned port2_id = channel_id * 2 + 1;
152 // Sanity checks to make sure our channel<->port converters are correct.
153 DCHECK(IS_OPENER_PORT_ID(port1_id));
154 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
155 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
156 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
157 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
158 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
159 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
165 MessageService::MessageService(BrowserContext* context)
166 : lazy_background_task_queue_(
167 ExtensionSystem::Get(context)->lazy_background_task_queue()),
168 weak_factory_(this) {
169 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
170 content::NotificationService::AllBrowserContextsAndSources());
171 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
172 content::NotificationService::AllBrowserContextsAndSources());
175 MessageService::~MessageService() {
176 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
180 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
181 g_factory = LAZY_INSTANCE_INITIALIZER;
184 BrowserContextKeyedAPIFactory<MessageService>*
185 MessageService::GetFactoryInstance() {
186 return g_factory.Pointer();
190 MessageService* MessageService::Get(BrowserContext* context) {
191 return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
194 void MessageService::OpenChannelToExtension(
195 int source_process_id, int source_routing_id, int receiver_port_id,
196 const std::string& source_extension_id,
197 const std::string& target_extension_id,
198 const GURL& source_url,
199 const std::string& channel_name,
200 bool include_tls_channel_id) {
201 content::RenderProcessHost* source =
202 content::RenderProcessHost::FromID(source_process_id);
205 BrowserContext* context = source->GetBrowserContext();
207 ExtensionSystem* extension_system = ExtensionSystem::Get(context);
208 DCHECK(extension_system);
209 const Extension* target_extension = extension_system->extension_service()->
210 extensions()->GetByID(target_extension_id);
211 if (!target_extension) {
212 DispatchOnDisconnect(
213 source, receiver_port_id, kReceivingEndDoesntExistError);
217 // Only running ephemeral apps can receive messages. Idle cached ephemeral
218 // apps are invisible and should not be connectable.
219 if (target_extension->is_ephemeral() &&
220 util::IsExtensionIdle(target_extension_id, context)) {
221 DispatchOnDisconnect(
222 source, receiver_port_id, kReceivingEndDoesntExistError);
226 bool is_web_connection = false;
228 if (source_extension_id != target_extension_id) {
229 // It's an external connection. Check the externally_connectable manifest
230 // key if it's present. If it's not, we allow connection from any extension
232 ExternallyConnectableInfo* externally_connectable =
233 static_cast<ExternallyConnectableInfo*>(
234 target_extension->GetManifestData(
235 manifest_keys::kExternallyConnectable));
236 bool is_externally_connectable = false;
238 if (externally_connectable) {
239 if (source_extension_id.empty()) {
240 // No source extension ID so the source was a web page. Check that the
242 is_web_connection = true;
243 is_externally_connectable =
244 externally_connectable->matches.MatchesURL(source_url);
245 // Only include the TLS channel ID for externally connected web pages.
246 include_tls_channel_id &=
247 is_externally_connectable &&
248 externally_connectable->accepts_tls_channel_id;
250 // Source extension ID so the source was an extension. Check that the
251 // extension matches.
252 is_externally_connectable =
253 externally_connectable->IdCanConnect(source_extension_id);
256 // Default behaviour. Any extension, no webpages.
257 is_externally_connectable = !source_extension_id.empty();
260 if (!is_externally_connectable) {
261 // Important: use kReceivingEndDoesntExistError here so that we don't
262 // leak information about this extension to callers. This way it's
263 // indistinguishable from the extension just not existing.
264 DispatchOnDisconnect(
265 source, receiver_port_id, kReceivingEndDoesntExistError);
270 WebContents* source_contents = tab_util::GetWebContentsByID(
271 source_process_id, source_routing_id);
273 if (context->IsOffTheRecord() &&
274 !util::IsIncognitoEnabled(target_extension_id, context)) {
275 // Give the user a chance to accept an incognito connection from the web if
276 // they haven't already, with the conditions:
277 // - Only for spanning-mode incognito. We don't want the complication of
278 // spinning up an additional process here which might need to do some
279 // setup that we're not expecting.
280 // - Only for extensions that can't normally be enabled in incognito, since
281 // that surface (e.g. chrome://extensions) should be the only one for
282 // enabling in incognito. In practice this means platform apps only.
283 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
284 target_extension->can_be_incognito_enabled() ||
285 // This check may show a dialog.
286 !IncognitoConnectability::Get(context)
287 ->Query(target_extension, source_contents, source_url)) {
288 DispatchOnDisconnect(
289 source, receiver_port_id, kReceivingEndDoesntExistError);
294 // Note: we use the source's profile here. If the source is an incognito
295 // process, we will use the incognito EPM to find the right extension process,
296 // which depends on whether the extension uses spanning or split mode.
297 MessagePort* receiver = new ExtensionMessagePort(
298 GetExtensionProcess(context, target_extension_id),
300 target_extension_id);
302 // Include info about the opener's tab (if it was a tab).
303 scoped_ptr<base::DictionaryValue> source_tab;
304 GURL source_url_for_tab;
306 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
307 // Only the tab id is useful to platform apps for internal use. The
308 // unnecessary bits will be stripped out in
309 // MessagingBindings::DispatchOnConnect().
310 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
311 source_url_for_tab = source_url;
314 OpenChannelParams* params = new OpenChannelParams(source,
322 include_tls_channel_id);
324 // If the target requests the TLS channel id, begin the lookup for it.
325 // The target might also be a lazy background page, checked next, but the
326 // loading of lazy background pages continues asynchronously, so enqueue
327 // messages awaiting TLS channel ID first.
328 if (include_tls_channel_id) {
329 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
330 = PendingMessagesQueue();
331 property_provider_.GetDomainBoundCert(
332 Profile::FromBrowserContext(context),
334 base::Bind(&MessageService::GotDomainBoundCert,
335 weak_factory_.GetWeakPtr(),
336 base::Passed(make_scoped_ptr(params))));
340 // The target might be a lazy background page. In that case, we have to check
341 // if it is loaded and ready, and if not, queue up the task and load the
343 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
344 context, target_extension, params)) {
348 OpenChannelImpl(make_scoped_ptr(params));
351 void MessageService::OpenChannelToNativeApp(
352 int source_process_id,
353 int source_routing_id,
354 int receiver_port_id,
355 const std::string& source_extension_id,
356 const std::string& native_app_name) {
357 content::RenderProcessHost* source =
358 content::RenderProcessHost::FromID(source_process_id);
362 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
363 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
364 ExtensionService* extension_service =
365 ExtensionSystem::Get(profile)->extension_service();
366 bool has_permission = false;
367 if (extension_service) {
368 const Extension* extension =
369 extension_service->GetExtensionById(source_extension_id, false);
370 has_permission = extension && extension->HasAPIPermission(
371 APIPermission::kNativeMessaging);
374 if (!has_permission) {
375 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
379 PrefService* pref_service = profile->GetPrefs();
381 // Verify that the host is not blocked by policies.
382 NativeMessageProcessHost::PolicyPermission policy_permission =
383 NativeMessageProcessHost::IsHostAllowed(pref_service, native_app_name);
384 if (policy_permission == NativeMessageProcessHost::DISALLOW) {
385 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
389 scoped_ptr<MessageChannel> channel(new MessageChannel());
390 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
391 source_extension_id));
393 // Get handle of the native view and pass it to the native messaging host.
394 gfx::NativeView native_view =
395 content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
396 GetView()->GetNativeView();
398 scoped_ptr<NativeMessageProcessHost> native_process =
399 NativeMessageProcessHost::Create(
401 base::WeakPtr<NativeMessageProcessHost::Client>(
402 weak_factory_.GetWeakPtr()),
403 source_extension_id, native_app_name, receiver_port_id,
404 policy_permission == NativeMessageProcessHost::ALLOW_ALL);
406 // Abandon the channel.
407 if (!native_process.get()) {
408 LOG(ERROR) << "Failed to create native process.";
409 DispatchOnDisconnect(
410 source, receiver_port_id, kReceivingEndDoesntExistError);
413 channel->receiver.reset(new NativeMessagePort(native_process.release()));
415 // Keep the opener alive until the channel is closed.
416 channel->opener->IncrementLazyKeepaliveCount();
418 AddChannel(channel.release(), receiver_port_id);
419 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
420 const char kNativeMessagingNotSupportedError[] =
421 "Native Messaging is not supported on this platform.";
422 DispatchOnDisconnect(
423 source, receiver_port_id, kNativeMessagingNotSupportedError);
424 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
427 void MessageService::OpenChannelToTab(
428 int source_process_id, int source_routing_id, int receiver_port_id,
429 int tab_id, const std::string& extension_id,
430 const std::string& channel_name) {
431 content::RenderProcessHost* source =
432 content::RenderProcessHost::FromID(source_process_id);
435 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
437 WebContents* contents = NULL;
438 scoped_ptr<MessagePort> receiver;
439 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
440 NULL, NULL, &contents, NULL)) {
441 receiver.reset(new ExtensionMessagePort(
442 contents->GetRenderProcessHost(),
443 contents->GetRenderViewHost()->GetRoutingID(),
447 if (contents && contents->GetController().NeedsReload()) {
448 // The tab isn't loaded yet. Don't attempt to connect.
449 DispatchOnDisconnect(
450 source, receiver_port_id, kReceivingEndDoesntExistError);
454 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
456 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
457 // for opening to tabs.
462 GURL(), // Source URL doesn't make sense for opening to tabs.
464 false)); // Connections to tabs don't get TLS channel IDs.
465 OpenChannelImpl(params.Pass());
468 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
470 return false; // Closed while in flight.
472 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
473 DispatchOnDisconnect(params->source,
474 params->receiver_port_id,
475 kReceivingEndDoesntExistError);
479 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
480 // http://code.google.com/p/chromium/issues/detail?id=19067
481 CHECK(params->receiver->GetRenderProcessHost());
483 MessageChannel* channel(new MessageChannel);
484 channel->opener.reset(new ExtensionMessagePort(params->source,
486 params->source_extension_id));
487 channel->receiver.reset(params->receiver.release());
489 CHECK(channel->receiver->GetRenderProcessHost());
491 AddChannel(channel, params->receiver_port_id);
493 CHECK(channel->receiver->GetRenderProcessHost());
495 // Send the connect event to the receiver. Give it the opener's port ID (the
496 // opener has the opposite port ID).
497 channel->receiver->DispatchOnConnect(params->receiver_port_id,
498 params->channel_name,
500 params->source_extension_id,
501 params->target_extension_id,
503 params->tls_channel_id);
505 // Keep both ends of the channel alive until the channel is closed.
506 channel->opener->IncrementLazyKeepaliveCount();
507 channel->receiver->IncrementLazyKeepaliveCount();
511 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
512 int channel_id = GET_CHANNEL_ID(receiver_port_id);
513 CHECK(channels_.find(channel_id) == channels_.end());
514 channels_[channel_id] = channel;
515 pending_lazy_background_page_channels_.erase(channel_id);
518 void MessageService::CloseChannel(int port_id,
519 const std::string& error_message) {
520 // Note: The channel might be gone already, if the other side closed first.
521 int channel_id = GET_CHANNEL_ID(port_id);
522 MessageChannelMap::iterator it = channels_.find(channel_id);
523 if (it == channels_.end()) {
524 PendingLazyBackgroundPageChannelMap::iterator pending =
525 pending_lazy_background_page_channels_.find(channel_id);
526 if (pending != pending_lazy_background_page_channels_.end()) {
527 lazy_background_task_queue_->AddPendingTask(
528 pending->second.first, pending->second.second,
529 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
530 weak_factory_.GetWeakPtr(), port_id, error_message));
534 CloseChannelImpl(it, port_id, error_message, true);
537 void MessageService::CloseChannelImpl(
538 MessageChannelMap::iterator channel_iter,
540 const std::string& error_message,
541 bool notify_other_port) {
542 MessageChannel* channel = channel_iter->second;
544 // Notify the other side.
545 if (notify_other_port) {
546 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
547 channel->receiver.get() : channel->opener.get();
548 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
552 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
553 channel->opener->DecrementLazyKeepaliveCount();
554 channel->receiver->DecrementLazyKeepaliveCount();
556 delete channel_iter->second;
557 channels_.erase(channel_iter);
560 void MessageService::PostMessage(int source_port_id, const Message& message) {
561 int channel_id = GET_CHANNEL_ID(source_port_id);
562 MessageChannelMap::iterator iter = channels_.find(channel_id);
563 if (iter == channels_.end()) {
564 // If this channel is pending, queue up the PostMessage to run once
565 // the channel opens.
566 EnqueuePendingMessage(source_port_id, channel_id, message);
570 DispatchMessage(source_port_id, iter->second, message);
573 void MessageService::PostMessageFromNativeProcess(int port_id,
574 const std::string& message) {
575 PostMessage(port_id, Message(message, false /* user_gesture */));
578 void MessageService::Observe(int type,
579 const content::NotificationSource& source,
580 const content::NotificationDetails& details) {
582 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
583 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
584 content::RenderProcessHost* renderer =
585 content::Source<content::RenderProcessHost>(source).ptr();
586 OnProcessClosed(renderer);
595 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
596 // Close any channels that share this renderer. We notify the opposite
597 // port that his pair has closed.
598 for (MessageChannelMap::iterator it = channels_.begin();
599 it != channels_.end(); ) {
600 MessageChannelMap::iterator current = it++;
602 content::RenderProcessHost* opener_process =
603 current->second->opener->GetRenderProcessHost();
604 content::RenderProcessHost* receiver_process =
605 current->second->receiver->GetRenderProcessHost();
607 // Only notify the other side if it has a different porocess host.
608 bool notify_other_port = opener_process && receiver_process &&
609 opener_process != receiver_process;
611 if (opener_process == process) {
612 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
613 std::string(), notify_other_port);
614 } else if (receiver_process == process) {
615 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
616 std::string(), notify_other_port);
621 void MessageService::EnqueuePendingMessage(int source_port_id,
623 const Message& message) {
624 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
625 pending_tls_channel_id_channels_.find(channel_id);
626 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
627 pending_for_tls_channel_id->second.push_back(
628 PendingMessage(source_port_id, message));
629 // Pending messages must only be pending the TLS channel ID or lazy
630 // background page loading, never both.
633 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
638 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
641 const Message& message) {
642 PendingLazyBackgroundPageChannelMap::iterator pending =
643 pending_lazy_background_page_channels_.find(channel_id);
644 if (pending != pending_lazy_background_page_channels_.end()) {
645 lazy_background_task_queue_->AddPendingTask(
646 pending->second.first, pending->second.second,
647 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
648 weak_factory_.GetWeakPtr(), source_port_id, message));
652 void MessageService::DispatchMessage(int source_port_id,
653 MessageChannel* channel,
654 const Message& message) {
655 // Figure out which port the ID corresponds to.
656 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
657 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
658 channel->opener.get() : channel->receiver.get();
660 port->DispatchOnMessage(message, dest_port_id);
663 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
664 BrowserContext* context,
665 const Extension* extension,
666 OpenChannelParams* params) {
667 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
670 // If the extension uses spanning incognito mode, make sure we're always
671 // using the original profile since that is what the extension process
673 if (!IncognitoInfo::IsSplitMode(extension))
674 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
676 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
679 pending_lazy_background_page_channels_
680 [GET_CHANNEL_ID(params->receiver_port_id)] =
681 PendingLazyBackgroundPageChannel(context, extension->id());
682 scoped_ptr<OpenChannelParams> scoped_params(params);
683 lazy_background_task_queue_->AddPendingTask(
686 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
687 weak_factory_.GetWeakPtr(),
688 base::Passed(&scoped_params),
689 params->source->GetID()));
693 void MessageService::GotDomainBoundCert(scoped_ptr<OpenChannelParams> params,
694 const std::string& tls_channel_id) {
695 params->tls_channel_id.assign(tls_channel_id);
696 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
698 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
699 pending_tls_channel_id_channels_.find(channel_id);
700 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
705 BrowserContext* context = params->source->GetBrowserContext();
707 const Extension* target_extension =
708 ExtensionSystem::Get(context)->extension_service()->extensions()->GetByID(
709 params->target_extension_id);
710 if (!target_extension) {
711 pending_tls_channel_id_channels_.erase(channel_id);
712 DispatchOnDisconnect(
713 params->source, params->receiver_port_id,
714 kReceivingEndDoesntExistError);
717 PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
718 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
719 context, target_extension, params.get())) {
720 // Lazy background queue took ownership. Release ours.
721 ignore_result(params.release());
722 // Messages queued up waiting for the TLS channel ID now need to be queued
723 // up for the lazy background page to load.
724 for (PendingMessagesQueue::iterator it = pending_messages.begin();
725 it != pending_messages.end();
727 EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
731 OpenChannelImpl(params.Pass());
732 // Messages queued up waiting for the TLS channel ID can be posted now.
733 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
734 if (channel_iter != channels_.end()) {
735 for (PendingMessagesQueue::iterator it = pending_messages.begin();
736 it != pending_messages.end();
738 DispatchMessage(it->first, channel_iter->second, it->second);
742 pending_tls_channel_id_channels_.erase(channel_id);
745 void MessageService::PendingLazyBackgroundPageOpenChannel(
746 scoped_ptr<OpenChannelParams> params,
747 int source_process_id,
748 ExtensionHost* host) {
750 return; // TODO(mpcomplete): notify source of disconnect?
752 // Re-lookup the source process since it may no longer be valid.
753 content::RenderProcessHost* source =
754 content::RenderProcessHost::FromID(source_process_id);
758 params->source = source;
759 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
761 params->target_extension_id));
762 OpenChannelImpl(params.Pass());
765 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
767 const std::string& error_message) {
768 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
769 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
772 } // namespace extensions