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_host.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/extensions/extension_tab_util.h"
23 #include "chrome/browser/extensions/extension_util.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/tab_contents/tab_util.h"
26 #include "chrome/common/extensions/extension_messages.h"
27 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/render_widget_host.h"
32 #include "content/public/browser/render_widget_host_view.h"
33 #include "content/public/browser/site_instance.h"
34 #include "content/public/browser/web_contents.h"
35 #include "extensions/browser/extension_system.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/manifest_constants.h"
40 #include "extensions/common/manifest_handlers/background_info.h"
41 #include "extensions/common/manifest_handlers/incognito_info.h"
42 #include "net/base/completion_callback.h"
45 using content::SiteInstance;
46 using content::WebContents;
48 // Since we have 2 ports for every channel, we just index channels by half the
50 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
51 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
52 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
54 // Port1 is always even, port2 is always odd.
55 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
57 // Change even to odd and vice versa, to get the other side of a given channel.
58 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
60 namespace extensions {
62 const char kReceivingEndDoesntExistError[] =
63 "Could not establish connection. Receiving end does not exist.";
64 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
65 const char kMissingPermissionError[] =
66 "Access to native messaging requires nativeMessaging permission.";
67 const char kProhibitedByPoliciesError[] =
68 "Access to the native messaging host was disabled by the system "
72 struct MessageService::MessageChannel {
73 scoped_ptr<MessagePort> opener;
74 scoped_ptr<MessagePort> receiver;
77 struct MessageService::OpenChannelParams {
78 content::RenderProcessHost* source;
79 base::DictionaryValue source_tab;
80 scoped_ptr<MessagePort> receiver;
82 std::string source_extension_id;
83 std::string target_extension_id;
85 std::string channel_name;
86 bool include_tls_channel_id;
87 std::string tls_channel_id;
89 // Takes ownership of receiver.
90 OpenChannelParams(content::RenderProcessHost* source,
91 scoped_ptr<base::DictionaryValue> source_tab,
92 MessagePort* receiver,
94 const std::string& source_extension_id,
95 const std::string& target_extension_id,
96 const GURL& source_url,
97 const std::string& channel_name,
98 bool include_tls_channel_id)
101 receiver_port_id(receiver_port_id),
102 source_extension_id(source_extension_id),
103 target_extension_id(target_extension_id),
104 source_url(source_url),
105 channel_name(channel_name),
106 include_tls_channel_id(include_tls_channel_id) {
108 this->source_tab.Swap(source_tab.get());
112 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
117 static base::StaticAtomicSequenceNumber g_next_channel_id;
118 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
120 static content::RenderProcessHost* GetExtensionProcess(
121 Profile* profile, const std::string& extension_id) {
122 SiteInstance* site_instance =
123 ExtensionSystem::Get(profile)->process_manager()->GetSiteInstanceForURL(
124 Extension::GetBaseURLFromExtensionId(extension_id));
125 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
130 content::RenderProcessHost*
131 MessageService::MessagePort::GetRenderProcessHost() {
136 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
137 unsigned channel_id =
138 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
140 if (channel_id == 0) {
141 int overflow_count = g_channel_id_overflow_count.GetNext();
142 if (overflow_count > 0)
143 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
146 unsigned port1_id = channel_id * 2;
147 unsigned port2_id = channel_id * 2 + 1;
149 // Sanity checks to make sure our channel<->port converters are correct.
150 DCHECK(IS_OPENER_PORT_ID(port1_id));
151 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
152 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
153 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
154 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
155 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
156 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
162 MessageService::MessageService(Profile* profile)
163 : lazy_background_task_queue_(
164 ExtensionSystem::Get(profile)->lazy_background_task_queue()),
165 weak_factory_(this) {
166 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
167 content::NotificationService::AllBrowserContextsAndSources());
168 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
169 content::NotificationService::AllBrowserContextsAndSources());
172 MessageService::~MessageService() {
173 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
177 static base::LazyInstance<ProfileKeyedAPIFactory<MessageService> >
178 g_factory = LAZY_INSTANCE_INITIALIZER;
181 ProfileKeyedAPIFactory<MessageService>* MessageService::GetFactoryInstance() {
182 return g_factory.Pointer();
186 MessageService* MessageService::Get(content::BrowserContext* context) {
187 Profile* profile = Profile::FromBrowserContext(context);
188 return ProfileKeyedAPIFactory<MessageService>::GetForProfile(profile);
191 void MessageService::OpenChannelToExtension(
192 int source_process_id, int source_routing_id, int receiver_port_id,
193 const std::string& source_extension_id,
194 const std::string& target_extension_id,
195 const GURL& source_url,
196 const std::string& channel_name,
197 bool include_tls_channel_id) {
198 content::RenderProcessHost* source =
199 content::RenderProcessHost::FromID(source_process_id);
202 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
204 ExtensionSystem* extension_system = ExtensionSystem::Get(profile);
205 DCHECK(extension_system);
206 const Extension* target_extension = extension_system->extension_service()->
207 extensions()->GetByID(target_extension_id);
208 if (!target_extension) {
209 DispatchOnDisconnect(
210 source, receiver_port_id, kReceivingEndDoesntExistError);
214 // Only running ephemeral apps can receive messages. Idle cached ephemeral
215 // apps are invisible and should not be connectable.
216 if (target_extension->is_ephemeral() &&
217 util::IsExtensionIdle(target_extension_id, profile)) {
218 DispatchOnDisconnect(
219 source, receiver_port_id, kReceivingEndDoesntExistError);
223 bool is_web_connection = false;
225 if (source_extension_id != target_extension_id) {
226 // It's an external connection. Check the externally_connectable manifest
227 // key if it's present. If it's not, we allow connection from any extension
229 ExternallyConnectableInfo* externally_connectable =
230 static_cast<ExternallyConnectableInfo*>(
231 target_extension->GetManifestData(
232 manifest_keys::kExternallyConnectable));
233 bool is_externally_connectable = false;
235 if (externally_connectable) {
236 if (source_extension_id.empty()) {
237 // No source extension ID so the source was a web page. Check that the
239 is_web_connection = true;
240 is_externally_connectable =
241 externally_connectable->matches.MatchesURL(source_url);
242 // Only include the TLS channel ID for externally connected web pages.
243 include_tls_channel_id &=
244 is_externally_connectable &&
245 externally_connectable->accepts_tls_channel_id;
247 // Source extension ID so the source was an extension. Check that the
248 // extension matches.
249 is_externally_connectable =
250 externally_connectable->IdCanConnect(source_extension_id);
253 // Default behaviour. Any extension, no webpages.
254 is_externally_connectable = !source_extension_id.empty();
257 if (!is_externally_connectable) {
258 // Important: use kReceivingEndDoesntExistError here so that we don't
259 // leak information about this extension to callers. This way it's
260 // indistinguishable from the extension just not existing.
261 DispatchOnDisconnect(
262 source, receiver_port_id, kReceivingEndDoesntExistError);
267 WebContents* source_contents = tab_util::GetWebContentsByID(
268 source_process_id, source_routing_id);
270 if (profile->IsOffTheRecord() &&
271 !util::IsIncognitoEnabled(target_extension_id, profile)) {
272 // Give the user a chance to accept an incognito connection if they haven't
273 // already - but only for spanning-mode incognito. We don't want the
274 // complication of spinning up an additional process here which might need
275 // to do some setup that we're not expecting.
276 if (!is_web_connection ||
277 IncognitoInfo::IsSplitMode(target_extension) ||
278 !IncognitoConnectability::Get(profile)->Query(target_extension,
281 DispatchOnDisconnect(
282 source, receiver_port_id, kReceivingEndDoesntExistError);
287 // Note: we use the source's profile here. If the source is an incognito
288 // process, we will use the incognito EPM to find the right extension process,
289 // which depends on whether the extension uses spanning or split mode.
290 MessagePort* receiver = new ExtensionMessagePort(
291 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL,
292 target_extension_id);
294 // Include info about the opener's tab (if it was a tab).
295 scoped_ptr<base::DictionaryValue> source_tab;
296 GURL source_url_for_tab;
298 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
299 // Only the tab id is useful to platform apps for internal use. The
300 // unnecessary bits will be stripped out in
301 // MessagingBindings::DispatchOnConnect().
302 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
303 source_url_for_tab = source_url;
306 OpenChannelParams* params = new OpenChannelParams(source,
314 include_tls_channel_id);
316 // If the target requests the TLS channel id, begin the lookup for it.
317 // The target might also be a lazy background page, checked next, but the
318 // loading of lazy background pages continues asynchronously, so enqueue
319 // messages awaiting TLS channel ID first.
320 if (include_tls_channel_id) {
321 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
322 = PendingMessagesQueue();
323 property_provider_.GetDomainBoundCert(
326 base::Bind(&MessageService::GotDomainBoundCert,
327 weak_factory_.GetWeakPtr(),
328 base::Passed(make_scoped_ptr(params))));
332 // The target might be a lazy background page. In that case, we have to check
333 // if it is loaded and ready, and if not, queue up the task and load the
335 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile,
341 OpenChannelImpl(make_scoped_ptr(params));
344 void MessageService::OpenChannelToNativeApp(
345 int source_process_id,
346 int source_routing_id,
347 int receiver_port_id,
348 const std::string& source_extension_id,
349 const std::string& native_app_name) {
350 content::RenderProcessHost* source =
351 content::RenderProcessHost::FromID(source_process_id);
355 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
356 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
357 ExtensionService* extension_service =
358 ExtensionSystem::Get(profile)->extension_service();
359 bool has_permission = false;
360 if (extension_service) {
361 const Extension* extension =
362 extension_service->GetExtensionById(source_extension_id, false);
363 has_permission = extension && extension->HasAPIPermission(
364 APIPermission::kNativeMessaging);
367 if (!has_permission) {
368 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
372 PrefService* pref_service = profile->GetPrefs();
374 // Verify that the host is not blocked by policies.
375 NativeMessageProcessHost::PolicyPermission policy_permission =
376 NativeMessageProcessHost::IsHostAllowed(pref_service, native_app_name);
377 if (policy_permission == NativeMessageProcessHost::DISALLOW) {
378 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
382 scoped_ptr<MessageChannel> channel(new MessageChannel());
383 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
384 source_extension_id));
386 // Get handle of the native view and pass it to the native messaging host.
387 gfx::NativeView native_view =
388 content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
389 GetView()->GetNativeView();
391 scoped_ptr<NativeMessageProcessHost> native_process =
392 NativeMessageProcessHost::Create(
394 base::WeakPtr<NativeMessageProcessHost::Client>(
395 weak_factory_.GetWeakPtr()),
396 source_extension_id, native_app_name, receiver_port_id,
397 policy_permission == NativeMessageProcessHost::ALLOW_ALL);
399 // Abandon the channel.
400 if (!native_process.get()) {
401 LOG(ERROR) << "Failed to create native process.";
402 DispatchOnDisconnect(
403 source, receiver_port_id, kReceivingEndDoesntExistError);
406 channel->receiver.reset(new NativeMessagePort(native_process.release()));
408 // Keep the opener alive until the channel is closed.
409 channel->opener->IncrementLazyKeepaliveCount();
411 AddChannel(channel.release(), receiver_port_id);
412 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
413 const char kNativeMessagingNotSupportedError[] =
414 "Native Messaging is not supported on this platform.";
415 DispatchOnDisconnect(
416 source, receiver_port_id, kNativeMessagingNotSupportedError);
417 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
420 void MessageService::OpenChannelToTab(
421 int source_process_id, int source_routing_id, int receiver_port_id,
422 int tab_id, const std::string& extension_id,
423 const std::string& channel_name) {
424 content::RenderProcessHost* source =
425 content::RenderProcessHost::FromID(source_process_id);
428 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
430 WebContents* contents = NULL;
431 scoped_ptr<MessagePort> receiver;
432 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
433 NULL, NULL, &contents, NULL)) {
434 receiver.reset(new ExtensionMessagePort(
435 contents->GetRenderProcessHost(),
436 contents->GetRenderViewHost()->GetRoutingID(),
440 if (contents && contents->GetController().NeedsReload()) {
441 // The tab isn't loaded yet. Don't attempt to connect.
442 DispatchOnDisconnect(
443 source, receiver_port_id, kReceivingEndDoesntExistError);
447 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
449 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
450 // for opening to tabs.
455 GURL(), // Source URL doesn't make sense for opening to tabs.
457 false)); // Connections to tabs don't get TLS channel IDs.
458 OpenChannelImpl(params.Pass());
461 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
463 return false; // Closed while in flight.
465 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
466 DispatchOnDisconnect(params->source,
467 params->receiver_port_id,
468 kReceivingEndDoesntExistError);
472 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
473 // http://code.google.com/p/chromium/issues/detail?id=19067
474 CHECK(params->receiver->GetRenderProcessHost());
476 MessageChannel* channel(new MessageChannel);
477 channel->opener.reset(new ExtensionMessagePort(params->source,
479 params->source_extension_id));
480 channel->receiver.reset(params->receiver.release());
482 CHECK(channel->receiver->GetRenderProcessHost());
484 AddChannel(channel, params->receiver_port_id);
486 CHECK(channel->receiver->GetRenderProcessHost());
488 // Send the connect event to the receiver. Give it the opener's port ID (the
489 // opener has the opposite port ID).
490 channel->receiver->DispatchOnConnect(params->receiver_port_id,
491 params->channel_name,
493 params->source_extension_id,
494 params->target_extension_id,
496 params->tls_channel_id);
498 // Keep both ends of the channel alive until the channel is closed.
499 channel->opener->IncrementLazyKeepaliveCount();
500 channel->receiver->IncrementLazyKeepaliveCount();
504 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
505 int channel_id = GET_CHANNEL_ID(receiver_port_id);
506 CHECK(channels_.find(channel_id) == channels_.end());
507 channels_[channel_id] = channel;
508 pending_lazy_background_page_channels_.erase(channel_id);
511 void MessageService::CloseChannel(int port_id,
512 const std::string& error_message) {
513 // Note: The channel might be gone already, if the other side closed first.
514 int channel_id = GET_CHANNEL_ID(port_id);
515 MessageChannelMap::iterator it = channels_.find(channel_id);
516 if (it == channels_.end()) {
517 PendingLazyBackgroundPageChannelMap::iterator pending =
518 pending_lazy_background_page_channels_.find(channel_id);
519 if (pending != pending_lazy_background_page_channels_.end()) {
520 lazy_background_task_queue_->AddPendingTask(
521 pending->second.first, pending->second.second,
522 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
523 weak_factory_.GetWeakPtr(), port_id, error_message));
527 CloseChannelImpl(it, port_id, error_message, true);
530 void MessageService::CloseChannelImpl(
531 MessageChannelMap::iterator channel_iter,
533 const std::string& error_message,
534 bool notify_other_port) {
535 MessageChannel* channel = channel_iter->second;
537 // Notify the other side.
538 if (notify_other_port) {
539 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
540 channel->receiver.get() : channel->opener.get();
541 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
545 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
546 channel->opener->DecrementLazyKeepaliveCount();
547 channel->receiver->DecrementLazyKeepaliveCount();
549 delete channel_iter->second;
550 channels_.erase(channel_iter);
553 void MessageService::PostMessage(int source_port_id, const Message& message) {
554 int channel_id = GET_CHANNEL_ID(source_port_id);
555 MessageChannelMap::iterator iter = channels_.find(channel_id);
556 if (iter == channels_.end()) {
557 // If this channel is pending, queue up the PostMessage to run once
558 // the channel opens.
559 EnqueuePendingMessage(source_port_id, channel_id, message);
563 DispatchMessage(source_port_id, iter->second, message);
566 void MessageService::PostMessageFromNativeProcess(int port_id,
567 const std::string& message) {
568 PostMessage(port_id, Message(message, false /* user_gesture */));
571 void MessageService::Observe(int type,
572 const content::NotificationSource& source,
573 const content::NotificationDetails& details) {
575 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
576 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
577 content::RenderProcessHost* renderer =
578 content::Source<content::RenderProcessHost>(source).ptr();
579 OnProcessClosed(renderer);
588 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
589 // Close any channels that share this renderer. We notify the opposite
590 // port that his pair has closed.
591 for (MessageChannelMap::iterator it = channels_.begin();
592 it != channels_.end(); ) {
593 MessageChannelMap::iterator current = it++;
595 content::RenderProcessHost* opener_process =
596 current->second->opener->GetRenderProcessHost();
597 content::RenderProcessHost* receiver_process =
598 current->second->receiver->GetRenderProcessHost();
600 // Only notify the other side if it has a different porocess host.
601 bool notify_other_port = opener_process && receiver_process &&
602 opener_process != receiver_process;
604 if (opener_process == process) {
605 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
606 std::string(), notify_other_port);
607 } else if (receiver_process == process) {
608 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
609 std::string(), notify_other_port);
614 void MessageService::EnqueuePendingMessage(int source_port_id,
616 const Message& message) {
617 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
618 pending_tls_channel_id_channels_.find(channel_id);
619 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
620 pending_for_tls_channel_id->second.push_back(
621 PendingMessage(source_port_id, message));
622 // Pending messages must only be pending the TLS channel ID or lazy
623 // background page loading, never both.
626 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
631 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
634 const Message& message) {
635 PendingLazyBackgroundPageChannelMap::iterator pending =
636 pending_lazy_background_page_channels_.find(channel_id);
637 if (pending != pending_lazy_background_page_channels_.end()) {
638 lazy_background_task_queue_->AddPendingTask(
639 pending->second.first, pending->second.second,
640 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
641 weak_factory_.GetWeakPtr(), source_port_id, message));
645 void MessageService::DispatchMessage(int source_port_id,
646 MessageChannel* channel,
647 const Message& message) {
648 // Figure out which port the ID corresponds to.
649 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
650 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
651 channel->opener.get() : channel->receiver.get();
653 port->DispatchOnMessage(message, dest_port_id);
656 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
658 const Extension* extension,
659 OpenChannelParams* params) {
660 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
663 // If the extension uses spanning incognito mode, make sure we're always
664 // using the original profile since that is what the extension process
666 if (!IncognitoInfo::IsSplitMode(extension))
667 profile = profile->GetOriginalProfile();
669 if (!lazy_background_task_queue_->ShouldEnqueueTask(profile, extension))
672 pending_lazy_background_page_channels_[
673 GET_CHANNEL_ID(params->receiver_port_id)] =
674 PendingLazyBackgroundPageChannel(profile, extension->id());
675 scoped_ptr<OpenChannelParams> scoped_params(params);
676 lazy_background_task_queue_->AddPendingTask(profile, extension->id(),
677 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
678 weak_factory_.GetWeakPtr(), base::Passed(&scoped_params),
679 params->source->GetID()));
683 void MessageService::GotDomainBoundCert(scoped_ptr<OpenChannelParams> params,
684 const std::string& tls_channel_id) {
685 params->tls_channel_id.assign(tls_channel_id);
686 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
688 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
689 pending_tls_channel_id_channels_.find(channel_id);
690 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
695 Profile* profile = Profile::FromBrowserContext(
696 params->source->GetBrowserContext());
698 const Extension* target_extension = ExtensionSystem::Get(profile)->
699 extension_service()->extensions()->GetByID(params->target_extension_id);
700 if (!target_extension) {
701 pending_tls_channel_id_channels_.erase(channel_id);
702 DispatchOnDisconnect(
703 params->source, params->receiver_port_id,
704 kReceivingEndDoesntExistError);
707 PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
708 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile,
711 // Lazy background queue took ownership. Release ours.
712 ignore_result(params.release());
713 // Messages queued up waiting for the TLS channel ID now need to be queued
714 // up for the lazy background page to load.
715 for (PendingMessagesQueue::iterator it = pending_messages.begin();
716 it != pending_messages.end();
718 EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
722 OpenChannelImpl(params.Pass());
723 // Messages queued up waiting for the TLS channel ID can be posted now.
724 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
725 if (channel_iter != channels_.end()) {
726 for (PendingMessagesQueue::iterator it = pending_messages.begin();
727 it != pending_messages.end();
729 DispatchMessage(it->first, channel_iter->second, it->second);
733 pending_tls_channel_id_channels_.erase(channel_id);
736 void MessageService::PendingLazyBackgroundPageOpenChannel(
737 scoped_ptr<OpenChannelParams> params,
738 int source_process_id,
739 ExtensionHost* host) {
741 return; // TODO(mpcomplete): notify source of disconnect?
743 // Re-lookup the source process since it may no longer be valid.
744 content::RenderProcessHost* source =
745 content::RenderProcessHost::FromID(source_process_id);
749 params->source = source;
750 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
752 params->target_extension_id));
753 OpenChannelImpl(params.Pass());
756 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
758 const std::string& error_message) {
759 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
760 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
763 } // namespace extensions