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/extension_host.h"
20 #include "chrome/browser/extensions/extension_process_manager.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/extensions/extension_system.h"
23 #include "chrome/browser/extensions/extension_tab_util.h"
24 #include "chrome/browser/extensions/extension_util.h"
25 #include "chrome/browser/extensions/process_map.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/tab_contents/tab_util.h"
28 #include "chrome/common/extensions/background_info.h"
29 #include "chrome/common/extensions/extension.h"
30 #include "chrome/common/extensions/extension_messages.h"
31 #include "chrome/common/extensions/incognito_handler.h"
32 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/render_widget_host.h"
37 #include "content/public/browser/render_widget_host_view.h"
38 #include "content/public/browser/site_instance.h"
39 #include "content/public/browser/web_contents.h"
40 #include "extensions/browser/lazy_background_task_queue.h"
41 #include "extensions/common/manifest_constants.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.";
69 struct MessageService::MessageChannel {
70 scoped_ptr<MessagePort> opener;
71 scoped_ptr<MessagePort> receiver;
74 struct MessageService::OpenChannelParams {
75 content::RenderProcessHost* source;
76 base::DictionaryValue source_tab;
77 scoped_ptr<MessagePort> receiver;
79 std::string source_extension_id;
80 std::string target_extension_id;
82 std::string channel_name;
83 bool include_tls_channel_id;
84 std::string tls_channel_id;
86 // Takes ownership of receiver.
87 OpenChannelParams(content::RenderProcessHost* source,
88 scoped_ptr<base::DictionaryValue> source_tab,
89 MessagePort* receiver,
91 const std::string& source_extension_id,
92 const std::string& target_extension_id,
93 const GURL& source_url,
94 const std::string& channel_name,
95 bool include_tls_channel_id)
98 receiver_port_id(receiver_port_id),
99 source_extension_id(source_extension_id),
100 target_extension_id(target_extension_id),
101 source_url(source_url),
102 channel_name(channel_name),
103 include_tls_channel_id(include_tls_channel_id) {
105 this->source_tab.Swap(source_tab.get());
109 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
114 static base::StaticAtomicSequenceNumber g_next_channel_id;
115 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
117 static content::RenderProcessHost* GetExtensionProcess(
118 Profile* profile, const std::string& extension_id) {
119 SiteInstance* site_instance =
120 ExtensionSystem::Get(profile)->process_manager()->
121 GetSiteInstanceForURL(
122 Extension::GetBaseURLFromExtensionId(extension_id));
124 if (!site_instance->HasProcess())
127 return site_instance->GetProcess();
132 content::RenderProcessHost*
133 MessageService::MessagePort::GetRenderProcessHost() {
138 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
139 unsigned channel_id =
140 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
142 if (channel_id == 0) {
143 int overflow_count = g_channel_id_overflow_count.GetNext();
144 if (overflow_count > 0)
145 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
148 unsigned port1_id = channel_id * 2;
149 unsigned port2_id = channel_id * 2 + 1;
151 // Sanity checks to make sure our channel<->port converters are correct.
152 DCHECK(IS_OPENER_PORT_ID(port1_id));
153 DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
154 DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
155 DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
156 DCHECK(GET_CHANNEL_ID(port1_id) == channel_id);
157 DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id);
158 DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id);
164 MessageService::MessageService(Profile* profile)
165 : lazy_background_task_queue_(
166 ExtensionSystem::Get(profile)->lazy_background_task_queue()),
167 weak_factory_(this) {
168 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
169 content::NotificationService::AllBrowserContextsAndSources());
170 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
171 content::NotificationService::AllBrowserContextsAndSources());
174 MessageService::~MessageService() {
175 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
179 static base::LazyInstance<ProfileKeyedAPIFactory<MessageService> >
180 g_factory = LAZY_INSTANCE_INITIALIZER;
183 ProfileKeyedAPIFactory<MessageService>* MessageService::GetFactoryInstance() {
184 return &g_factory.Get();
188 MessageService* MessageService::Get(Profile* profile) {
189 return ProfileKeyedAPIFactory<MessageService>::GetForProfile(profile);
192 void MessageService::OpenChannelToExtension(
193 int source_process_id, int source_routing_id, int receiver_port_id,
194 const std::string& source_extension_id,
195 const std::string& target_extension_id,
196 const GURL& source_url,
197 const std::string& channel_name,
198 bool include_tls_channel_id) {
199 content::RenderProcessHost* source =
200 content::RenderProcessHost::FromID(source_process_id);
203 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
205 const Extension* target_extension = ExtensionSystem::Get(profile)->
206 extension_service()->extensions()->GetByID(target_extension_id);
207 if (!target_extension) {
208 DispatchOnDisconnect(
209 source, receiver_port_id, kReceivingEndDoesntExistError);
213 bool is_web_connection = false;
215 if (source_extension_id != target_extension_id) {
216 // It's an external connection. Check the externally_connectable manifest
217 // key if it's present. If it's not, we allow connection from any extension
219 ExternallyConnectableInfo* externally_connectable =
220 static_cast<ExternallyConnectableInfo*>(
221 target_extension->GetManifestData(
222 manifest_keys::kExternallyConnectable));
223 bool is_externally_connectable = false;
225 if (externally_connectable) {
226 if (source_extension_id.empty()) {
227 // No source extension ID so the source was a web page. Check that the
229 is_web_connection = true;
230 is_externally_connectable =
231 externally_connectable->matches.MatchesURL(source_url);
232 // Only include the TLS channel ID for externally connected web pages.
233 include_tls_channel_id &=
234 is_externally_connectable &&
235 externally_connectable->accepts_tls_channel_id;
237 // Source extension ID so the source was an extension. Check that the
238 // extension matches.
239 is_externally_connectable =
240 externally_connectable->IdCanConnect(source_extension_id);
243 // Default behaviour. Any extension, no webpages.
244 is_externally_connectable = !source_extension_id.empty();
247 if (!is_externally_connectable) {
248 // Important: use kReceivingEndDoesntExistError here so that we don't
249 // leak information about this extension to callers. This way it's
250 // indistinguishable from the extension just not existing.
251 DispatchOnDisconnect(
252 source, receiver_port_id, kReceivingEndDoesntExistError);
257 ExtensionService* extension_service =
258 ExtensionSystem::Get(profile)->extension_service();
259 WebContents* source_contents = tab_util::GetWebContentsByID(
260 source_process_id, source_routing_id);
262 if (profile->IsOffTheRecord() &&
263 !extension_util::IsIncognitoEnabled(target_extension_id,
264 extension_service)) {
265 // Give the user a chance to accept an incognito connection if they haven't
266 // already - but only for spanning-mode incognito. We don't want the
267 // complication of spinning up an additional process here which might need
268 // to do some setup that we're not expecting.
269 if (!is_web_connection ||
270 IncognitoInfo::IsSplitMode(target_extension) ||
271 !IncognitoConnectability::Get(profile)->Query(target_extension,
274 DispatchOnDisconnect(
275 source, receiver_port_id, kReceivingEndDoesntExistError);
280 // Note: we use the source's profile here. If the source is an incognito
281 // process, we will use the incognito EPM to find the right extension process,
282 // which depends on whether the extension uses spanning or split mode.
283 MessagePort* receiver = new ExtensionMessagePort(
284 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL,
285 target_extension_id);
287 // Include info about the opener's tab (if it was a tab).
288 scoped_ptr<base::DictionaryValue> source_tab;
289 GURL source_url_for_tab;
291 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
292 // Platform apps can be sent messages, but don't have a Tab concept.
293 if (!target_extension->is_platform_app())
294 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
295 source_url_for_tab = source_url;
298 OpenChannelParams* params = new OpenChannelParams(source,
306 include_tls_channel_id);
308 // If the target requests the TLS channel id, begin the lookup for it.
309 // The target might also be a lazy background page, checked next, but the
310 // loading of lazy background pages continues asynchronously, so enqueue
311 // messages awaiting TLS channel ID first.
312 if (include_tls_channel_id) {
313 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
314 = PendingMessagesQueue();
315 property_provider_.GetDomainBoundCert(profile, params->source_url,
316 base::Bind(&MessageService::GotDomainBoundCert,
317 weak_factory_.GetWeakPtr(),
318 base::Passed(make_scoped_ptr(params))));
322 // The target might be a lazy background page. In that case, we have to check
323 // if it is loaded and ready, and if not, queue up the task and load the
325 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile,
331 OpenChannelImpl(make_scoped_ptr(params));
334 void MessageService::OpenChannelToNativeApp(
335 int source_process_id,
336 int source_routing_id,
337 int receiver_port_id,
338 const std::string& source_extension_id,
339 const std::string& native_app_name) {
340 content::RenderProcessHost* source =
341 content::RenderProcessHost::FromID(source_process_id);
345 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
346 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
347 ExtensionService* extension_service =
348 ExtensionSystem::Get(profile)->extension_service();
349 bool has_permission = false;
350 if (extension_service) {
351 const Extension* extension =
352 extension_service->GetExtensionById(source_extension_id, false);
353 has_permission = extension && extension->HasAPIPermission(
354 APIPermission::kNativeMessaging);
357 if (!has_permission) {
358 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
362 scoped_ptr<MessageChannel> channel(new MessageChannel());
363 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
364 source_extension_id));
366 // Get handle of the native view and pass it to the native messaging host.
367 gfx::NativeView native_view =
368 content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
369 GetView()->GetNativeView();
371 scoped_ptr<NativeMessageProcessHost> native_process =
372 NativeMessageProcessHost::Create(
374 base::WeakPtr<NativeMessageProcessHost::Client>(
375 weak_factory_.GetWeakPtr()),
376 source_extension_id, native_app_name, receiver_port_id);
378 // Abandon the channel.
379 if (!native_process.get()) {
380 LOG(ERROR) << "Failed to create native process.";
381 DispatchOnDisconnect(
382 source, receiver_port_id, kReceivingEndDoesntExistError);
385 channel->receiver.reset(new NativeMessagePort(native_process.release()));
387 // Keep the opener alive until the channel is closed.
388 channel->opener->IncrementLazyKeepaliveCount();
390 AddChannel(channel.release(), receiver_port_id);
391 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
392 const char kNativeMessagingNotSupportedError[] =
393 "Native Messaging is not supported on this platform.";
394 DispatchOnDisconnect(
395 source, receiver_port_id, kNativeMessagingNotSupportedError);
396 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
399 void MessageService::OpenChannelToTab(
400 int source_process_id, int source_routing_id, int receiver_port_id,
401 int tab_id, const std::string& extension_id,
402 const std::string& channel_name) {
403 content::RenderProcessHost* source =
404 content::RenderProcessHost::FromID(source_process_id);
407 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
409 WebContents* contents = NULL;
410 scoped_ptr<MessagePort> receiver;
411 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
412 NULL, NULL, &contents, NULL)) {
413 receiver.reset(new ExtensionMessagePort(
414 contents->GetRenderProcessHost(),
415 contents->GetRenderViewHost()->GetRoutingID(),
419 if (contents && contents->GetController().NeedsReload()) {
420 // The tab isn't loaded yet. Don't attempt to connect.
421 DispatchOnDisconnect(
422 source, receiver_port_id, kReceivingEndDoesntExistError);
426 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
428 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
429 // for opening to tabs.
434 GURL(), // Source URL doesn't make sense for opening to tabs.
436 false)); // Connections to tabs don't get TLS channel IDs.
437 OpenChannelImpl(params.Pass());
440 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
442 return false; // Closed while in flight.
444 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
445 DispatchOnDisconnect(params->source,
446 params->receiver_port_id,
447 kReceivingEndDoesntExistError);
451 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
452 // http://code.google.com/p/chromium/issues/detail?id=19067
453 CHECK(params->receiver->GetRenderProcessHost());
455 MessageChannel* channel(new MessageChannel);
456 channel->opener.reset(new ExtensionMessagePort(params->source,
458 params->source_extension_id));
459 channel->receiver.reset(params->receiver.release());
461 CHECK(channel->receiver->GetRenderProcessHost());
463 AddChannel(channel, params->receiver_port_id);
465 CHECK(channel->receiver->GetRenderProcessHost());
467 // Send the connect event to the receiver. Give it the opener's port ID (the
468 // opener has the opposite port ID).
469 channel->receiver->DispatchOnConnect(params->receiver_port_id,
470 params->channel_name,
472 params->source_extension_id,
473 params->target_extension_id,
475 params->tls_channel_id);
477 // Keep both ends of the channel alive until the channel is closed.
478 channel->opener->IncrementLazyKeepaliveCount();
479 channel->receiver->IncrementLazyKeepaliveCount();
483 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
484 int channel_id = GET_CHANNEL_ID(receiver_port_id);
485 CHECK(channels_.find(channel_id) == channels_.end());
486 channels_[channel_id] = channel;
487 pending_lazy_background_page_channels_.erase(channel_id);
490 void MessageService::CloseChannel(int port_id,
491 const std::string& error_message) {
492 // Note: The channel might be gone already, if the other side closed first.
493 int channel_id = GET_CHANNEL_ID(port_id);
494 MessageChannelMap::iterator it = channels_.find(channel_id);
495 if (it == channels_.end()) {
496 PendingLazyBackgroundPageChannelMap::iterator pending =
497 pending_lazy_background_page_channels_.find(channel_id);
498 if (pending != pending_lazy_background_page_channels_.end()) {
499 lazy_background_task_queue_->AddPendingTask(
500 pending->second.first, pending->second.second,
501 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
502 weak_factory_.GetWeakPtr(), port_id, error_message));
506 CloseChannelImpl(it, port_id, error_message, true);
509 void MessageService::CloseChannelImpl(
510 MessageChannelMap::iterator channel_iter,
512 const std::string& error_message,
513 bool notify_other_port) {
514 MessageChannel* channel = channel_iter->second;
516 // Notify the other side.
517 if (notify_other_port) {
518 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
519 channel->receiver.get() : channel->opener.get();
520 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
524 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
525 channel->opener->DecrementLazyKeepaliveCount();
526 channel->receiver->DecrementLazyKeepaliveCount();
528 delete channel_iter->second;
529 channels_.erase(channel_iter);
532 void MessageService::PostMessage(
533 int source_port_id, const Message& message) {
534 int channel_id = GET_CHANNEL_ID(source_port_id);
535 MessageChannelMap::iterator iter = channels_.find(channel_id);
536 if (iter == channels_.end()) {
537 // If this channel is pending, queue up the PostMessage to run once
538 // the channel opens.
539 EnqueuePendingMessage(source_port_id, channel_id, message);
543 DispatchMessage(source_port_id, iter->second, message);
546 void MessageService::PostMessageFromNativeProcess(int port_id,
547 const std::string& message) {
548 PostMessage(port_id, Message(message, false /* user_gesture */));
551 void MessageService::Observe(int type,
552 const content::NotificationSource& source,
553 const content::NotificationDetails& details) {
555 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
556 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
557 content::RenderProcessHost* renderer =
558 content::Source<content::RenderProcessHost>(source).ptr();
559 OnProcessClosed(renderer);
568 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
569 // Close any channels that share this renderer. We notify the opposite
570 // port that his pair has closed.
571 for (MessageChannelMap::iterator it = channels_.begin();
572 it != channels_.end(); ) {
573 MessageChannelMap::iterator current = it++;
575 content::RenderProcessHost* opener_process =
576 current->second->opener->GetRenderProcessHost();
577 content::RenderProcessHost* receiver_process =
578 current->second->receiver->GetRenderProcessHost();
580 // Only notify the other side if it has a different porocess host.
581 bool notify_other_port = opener_process && receiver_process &&
582 opener_process != receiver_process;
584 if (opener_process == process) {
585 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
586 std::string(), notify_other_port);
587 } else if (receiver_process == process) {
588 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
589 std::string(), notify_other_port);
594 void MessageService::EnqueuePendingMessage(int source_port_id,
596 const Message& message) {
597 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
598 pending_tls_channel_id_channels_.find(channel_id);
599 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
600 pending_for_tls_channel_id->second.push_back(
601 PendingMessage(source_port_id, message));
602 // Pending messages must only be pending the TLS channel ID or lazy
603 // background page loading, never both.
606 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
611 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
614 const Message& message) {
615 PendingLazyBackgroundPageChannelMap::iterator pending =
616 pending_lazy_background_page_channels_.find(channel_id);
617 if (pending != pending_lazy_background_page_channels_.end()) {
618 lazy_background_task_queue_->AddPendingTask(
619 pending->second.first, pending->second.second,
620 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
621 weak_factory_.GetWeakPtr(), source_port_id, message));
625 void MessageService::DispatchMessage(int source_port_id,
626 MessageChannel* channel,
627 const Message& message) {
628 // Figure out which port the ID corresponds to.
629 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
630 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
631 channel->opener.get() : channel->receiver.get();
633 port->DispatchOnMessage(message, dest_port_id);
636 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
638 const Extension* extension,
639 OpenChannelParams* params) {
640 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
643 // If the extension uses spanning incognito mode, make sure we're always
644 // using the original profile since that is what the extension process
646 if (!IncognitoInfo::IsSplitMode(extension))
647 profile = profile->GetOriginalProfile();
649 if (!lazy_background_task_queue_->ShouldEnqueueTask(profile, extension))
652 pending_lazy_background_page_channels_[
653 GET_CHANNEL_ID(params->receiver_port_id)] =
654 PendingLazyBackgroundPageChannel(profile, extension->id());
655 scoped_ptr<OpenChannelParams> scoped_params(params);
656 lazy_background_task_queue_->AddPendingTask(profile, extension->id(),
657 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
658 weak_factory_.GetWeakPtr(), base::Passed(&scoped_params),
659 params->source->GetID()));
663 void MessageService::GotDomainBoundCert(scoped_ptr<OpenChannelParams> params,
664 const std::string& tls_channel_id) {
665 params->tls_channel_id.assign(tls_channel_id);
666 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
668 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
669 pending_tls_channel_id_channels_.find(channel_id);
670 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
675 Profile* profile = Profile::FromBrowserContext(
676 params->source->GetBrowserContext());
678 const Extension* target_extension = ExtensionSystem::Get(profile)->
679 extension_service()->extensions()->GetByID(params->target_extension_id);
680 if (!target_extension) {
681 pending_tls_channel_id_channels_.erase(channel_id);
682 DispatchOnDisconnect(
683 params->source, params->receiver_port_id,
684 kReceivingEndDoesntExistError);
687 PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
688 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile,
691 // Lazy background queue took ownership. Release ours.
692 ignore_result(params.release());
693 // Messages queued up waiting for the TLS channel ID now need to be queued
694 // up for the lazy background page to load.
695 for (PendingMessagesQueue::iterator it = pending_messages.begin();
696 it != pending_messages.end();
698 EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
702 OpenChannelImpl(params.Pass());
703 // Messages queued up waiting for the TLS channel ID can be posted now.
704 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
705 if (channel_iter != channels_.end()) {
706 for (PendingMessagesQueue::iterator it = pending_messages.begin();
707 it != pending_messages.end();
709 DispatchMessage(it->first, channel_iter->second, it->second);
713 pending_tls_channel_id_channels_.erase(channel_id);
716 void MessageService::PendingLazyBackgroundPageOpenChannel(
717 scoped_ptr<OpenChannelParams> params,
718 int source_process_id,
719 ExtensionHost* host) {
721 return; // TODO(mpcomplete): notify source of disconnect?
723 // Re-lookup the source process since it may no longer be valid.
724 content::RenderProcessHost* source =
725 content::RenderProcessHost::FromID(source_process_id);
729 params->source = source;
730 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
732 params->target_extension_id));
733 OpenChannelImpl(params.Pass());
736 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
738 const std::string& error_message) {
739 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
740 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
743 } // namespace extensions