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/manifest_constants.h"
39 #include "extensions/common/manifest_handlers/background_info.h"
40 #include "extensions/common/manifest_handlers/externally_connectable.h"
41 #include "extensions/common/manifest_handlers/incognito_info.h"
42 #include "extensions/common/permissions/permissions_data.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 bool is_web_connection = false;
219 if (source_extension_id != target_extension_id) {
220 // It's an external connection. Check the externally_connectable manifest
221 // key if it's present. If it's not, we allow connection from any extension
223 ExternallyConnectableInfo* externally_connectable =
224 static_cast<ExternallyConnectableInfo*>(
225 target_extension->GetManifestData(
226 manifest_keys::kExternallyConnectable));
227 bool is_externally_connectable = false;
229 if (externally_connectable) {
230 if (source_extension_id.empty()) {
231 // No source extension ID so the source was a web page. Check that the
233 is_web_connection = true;
234 is_externally_connectable =
235 externally_connectable->matches.MatchesURL(source_url);
236 // Only include the TLS channel ID for externally connected web pages.
237 include_tls_channel_id &=
238 is_externally_connectable &&
239 externally_connectable->accepts_tls_channel_id;
241 // Source extension ID so the source was an extension. Check that the
242 // extension matches.
243 is_externally_connectable =
244 externally_connectable->IdCanConnect(source_extension_id);
247 // Default behaviour. Any extension, no webpages.
248 is_externally_connectable = !source_extension_id.empty();
251 if (!is_externally_connectable) {
252 // Important: use kReceivingEndDoesntExistError here so that we don't
253 // leak information about this extension to callers. This way it's
254 // indistinguishable from the extension just not existing.
255 DispatchOnDisconnect(
256 source, receiver_port_id, kReceivingEndDoesntExistError);
261 WebContents* source_contents = tab_util::GetWebContentsByID(
262 source_process_id, source_routing_id);
264 if (context->IsOffTheRecord() &&
265 !util::IsIncognitoEnabled(target_extension_id, context)) {
266 // Give the user a chance to accept an incognito connection from the web if
267 // they haven't already, with the conditions:
268 // - Only for spanning-mode incognito. We don't want the complication of
269 // spinning up an additional process here which might need to do some
270 // setup that we're not expecting.
271 // - Only for extensions that can't normally be enabled in incognito, since
272 // that surface (e.g. chrome://extensions) should be the only one for
273 // enabling in incognito. In practice this means platform apps only.
274 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
275 target_extension->can_be_incognito_enabled() ||
276 // This check may show a dialog.
277 !IncognitoConnectability::Get(context)
278 ->Query(target_extension, source_contents, source_url)) {
279 DispatchOnDisconnect(
280 source, receiver_port_id, kReceivingEndDoesntExistError);
285 // Note: we use the source's profile here. If the source is an incognito
286 // process, we will use the incognito EPM to find the right extension process,
287 // which depends on whether the extension uses spanning or split mode.
288 MessagePort* receiver = new ExtensionMessagePort(
289 GetExtensionProcess(context, target_extension_id),
291 target_extension_id);
293 // Include info about the opener's tab (if it was a tab).
294 scoped_ptr<base::DictionaryValue> source_tab;
295 GURL source_url_for_tab;
297 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
298 // Only the tab id is useful to platform apps for internal use. The
299 // unnecessary bits will be stripped out in
300 // MessagingBindings::DispatchOnConnect().
301 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
302 source_url_for_tab = source_url;
305 OpenChannelParams* params = new OpenChannelParams(source,
313 include_tls_channel_id);
315 // If the target requests the TLS channel id, begin the lookup for it.
316 // The target might also be a lazy background page, checked next, but the
317 // loading of lazy background pages continues asynchronously, so enqueue
318 // messages awaiting TLS channel ID first.
319 if (include_tls_channel_id) {
320 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
321 = PendingMessagesQueue();
322 property_provider_.GetChannelID(
323 Profile::FromBrowserContext(context),
325 base::Bind(&MessageService::GotChannelID,
326 weak_factory_.GetWeakPtr(),
327 base::Passed(make_scoped_ptr(params))));
331 // The target might be a lazy background page. In that case, we have to check
332 // if it is loaded and ready, and if not, queue up the task and load the
334 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
335 context, target_extension, params)) {
339 OpenChannelImpl(make_scoped_ptr(params));
342 void MessageService::OpenChannelToNativeApp(
343 int source_process_id,
344 int source_routing_id,
345 int receiver_port_id,
346 const std::string& source_extension_id,
347 const std::string& native_app_name) {
348 content::RenderProcessHost* source =
349 content::RenderProcessHost::FromID(source_process_id);
353 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
354 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
355 ExtensionService* extension_service =
356 ExtensionSystem::Get(profile)->extension_service();
357 bool has_permission = false;
358 if (extension_service) {
359 const Extension* extension =
360 extension_service->GetExtensionById(source_extension_id, false);
361 has_permission = extension &&
362 extension->permissions_data()->HasAPIPermission(
363 APIPermission::kNativeMessaging);
366 if (!has_permission) {
367 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
371 PrefService* pref_service = profile->GetPrefs();
373 // Verify that the host is not blocked by policies.
374 NativeMessageProcessHost::PolicyPermission policy_permission =
375 NativeMessageProcessHost::IsHostAllowed(pref_service, native_app_name);
376 if (policy_permission == NativeMessageProcessHost::DISALLOW) {
377 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
381 scoped_ptr<MessageChannel> channel(new MessageChannel());
382 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
383 source_extension_id));
385 // Get handle of the native view and pass it to the native messaging host.
386 gfx::NativeView native_view =
387 content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
388 GetView()->GetNativeView();
390 scoped_ptr<NativeMessageProcessHost> native_process =
391 NativeMessageProcessHost::Create(
393 base::WeakPtr<NativeMessageProcessHost::Client>(
394 weak_factory_.GetWeakPtr()),
395 source_extension_id, native_app_name, receiver_port_id,
396 policy_permission == NativeMessageProcessHost::ALLOW_ALL);
398 // Abandon the channel.
399 if (!native_process.get()) {
400 LOG(ERROR) << "Failed to create native process.";
401 DispatchOnDisconnect(
402 source, receiver_port_id, kReceivingEndDoesntExistError);
405 channel->receiver.reset(new NativeMessagePort(native_process.release()));
407 // Keep the opener alive until the channel is closed.
408 channel->opener->IncrementLazyKeepaliveCount();
410 AddChannel(channel.release(), receiver_port_id);
411 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
412 const char kNativeMessagingNotSupportedError[] =
413 "Native Messaging is not supported on this platform.";
414 DispatchOnDisconnect(
415 source, receiver_port_id, kNativeMessagingNotSupportedError);
416 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
419 void MessageService::OpenChannelToTab(
420 int source_process_id, int source_routing_id, int receiver_port_id,
421 int tab_id, const std::string& extension_id,
422 const std::string& channel_name) {
423 content::RenderProcessHost* source =
424 content::RenderProcessHost::FromID(source_process_id);
427 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
429 WebContents* contents = NULL;
430 scoped_ptr<MessagePort> receiver;
431 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
432 NULL, NULL, &contents, NULL)) {
433 receiver.reset(new ExtensionMessagePort(
434 contents->GetRenderProcessHost(),
435 contents->GetRenderViewHost()->GetRoutingID(),
439 if (contents && contents->GetController().NeedsReload()) {
440 // The tab isn't loaded yet. Don't attempt to connect.
441 DispatchOnDisconnect(
442 source, receiver_port_id, kReceivingEndDoesntExistError);
446 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
448 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
449 // for opening to tabs.
454 GURL(), // Source URL doesn't make sense for opening to tabs.
456 false)); // Connections to tabs don't get TLS channel IDs.
457 OpenChannelImpl(params.Pass());
460 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
462 return false; // Closed while in flight.
464 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
465 DispatchOnDisconnect(params->source,
466 params->receiver_port_id,
467 kReceivingEndDoesntExistError);
471 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
472 // http://code.google.com/p/chromium/issues/detail?id=19067
473 CHECK(params->receiver->GetRenderProcessHost());
475 MessageChannel* channel(new MessageChannel);
476 channel->opener.reset(new ExtensionMessagePort(params->source,
478 params->source_extension_id));
479 channel->receiver.reset(params->receiver.release());
481 CHECK(channel->receiver->GetRenderProcessHost());
483 AddChannel(channel, params->receiver_port_id);
485 CHECK(channel->receiver->GetRenderProcessHost());
487 // Send the connect event to the receiver. Give it the opener's port ID (the
488 // opener has the opposite port ID).
489 channel->receiver->DispatchOnConnect(params->receiver_port_id,
490 params->channel_name,
492 params->source_extension_id,
493 params->target_extension_id,
495 params->tls_channel_id);
497 // Keep both ends of the channel alive until the channel is closed.
498 channel->opener->IncrementLazyKeepaliveCount();
499 channel->receiver->IncrementLazyKeepaliveCount();
503 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
504 int channel_id = GET_CHANNEL_ID(receiver_port_id);
505 CHECK(channels_.find(channel_id) == channels_.end());
506 channels_[channel_id] = channel;
507 pending_lazy_background_page_channels_.erase(channel_id);
510 void MessageService::CloseChannel(int port_id,
511 const std::string& error_message) {
512 // Note: The channel might be gone already, if the other side closed first.
513 int channel_id = GET_CHANNEL_ID(port_id);
514 MessageChannelMap::iterator it = channels_.find(channel_id);
515 if (it == channels_.end()) {
516 PendingLazyBackgroundPageChannelMap::iterator pending =
517 pending_lazy_background_page_channels_.find(channel_id);
518 if (pending != pending_lazy_background_page_channels_.end()) {
519 lazy_background_task_queue_->AddPendingTask(
520 pending->second.first, pending->second.second,
521 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
522 weak_factory_.GetWeakPtr(), port_id, error_message));
526 CloseChannelImpl(it, port_id, error_message, true);
529 void MessageService::CloseChannelImpl(
530 MessageChannelMap::iterator channel_iter,
532 const std::string& error_message,
533 bool notify_other_port) {
534 MessageChannel* channel = channel_iter->second;
536 // Notify the other side.
537 if (notify_other_port) {
538 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
539 channel->receiver.get() : channel->opener.get();
540 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
544 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
545 channel->opener->DecrementLazyKeepaliveCount();
546 channel->receiver->DecrementLazyKeepaliveCount();
548 delete channel_iter->second;
549 channels_.erase(channel_iter);
552 void MessageService::PostMessage(int source_port_id, const Message& message) {
553 int channel_id = GET_CHANNEL_ID(source_port_id);
554 MessageChannelMap::iterator iter = channels_.find(channel_id);
555 if (iter == channels_.end()) {
556 // If this channel is pending, queue up the PostMessage to run once
557 // the channel opens.
558 EnqueuePendingMessage(source_port_id, channel_id, message);
562 DispatchMessage(source_port_id, iter->second, message);
565 void MessageService::PostMessageFromNativeProcess(int port_id,
566 const std::string& message) {
567 PostMessage(port_id, Message(message, false /* user_gesture */));
570 void MessageService::Observe(int type,
571 const content::NotificationSource& source,
572 const content::NotificationDetails& details) {
574 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
575 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
576 content::RenderProcessHost* renderer =
577 content::Source<content::RenderProcessHost>(source).ptr();
578 OnProcessClosed(renderer);
587 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
588 // Close any channels that share this renderer. We notify the opposite
589 // port that his pair has closed.
590 for (MessageChannelMap::iterator it = channels_.begin();
591 it != channels_.end(); ) {
592 MessageChannelMap::iterator current = it++;
594 content::RenderProcessHost* opener_process =
595 current->second->opener->GetRenderProcessHost();
596 content::RenderProcessHost* receiver_process =
597 current->second->receiver->GetRenderProcessHost();
599 // Only notify the other side if it has a different porocess host.
600 bool notify_other_port = opener_process && receiver_process &&
601 opener_process != receiver_process;
603 if (opener_process == process) {
604 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
605 std::string(), notify_other_port);
606 } else if (receiver_process == process) {
607 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
608 std::string(), notify_other_port);
613 void MessageService::EnqueuePendingMessage(int source_port_id,
615 const Message& message) {
616 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
617 pending_tls_channel_id_channels_.find(channel_id);
618 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
619 pending_for_tls_channel_id->second.push_back(
620 PendingMessage(source_port_id, message));
621 // Pending messages must only be pending the TLS channel ID or lazy
622 // background page loading, never both.
625 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
630 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
633 const Message& message) {
634 PendingLazyBackgroundPageChannelMap::iterator pending =
635 pending_lazy_background_page_channels_.find(channel_id);
636 if (pending != pending_lazy_background_page_channels_.end()) {
637 lazy_background_task_queue_->AddPendingTask(
638 pending->second.first, pending->second.second,
639 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
640 weak_factory_.GetWeakPtr(), source_port_id, message));
644 void MessageService::DispatchMessage(int source_port_id,
645 MessageChannel* channel,
646 const Message& message) {
647 // Figure out which port the ID corresponds to.
648 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
649 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
650 channel->opener.get() : channel->receiver.get();
652 port->DispatchOnMessage(message, dest_port_id);
655 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
656 BrowserContext* context,
657 const Extension* extension,
658 OpenChannelParams* params) {
659 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
662 // If the extension uses spanning incognito mode, make sure we're always
663 // using the original profile since that is what the extension process
665 if (!IncognitoInfo::IsSplitMode(extension))
666 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
668 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
671 pending_lazy_background_page_channels_
672 [GET_CHANNEL_ID(params->receiver_port_id)] =
673 PendingLazyBackgroundPageChannel(context, extension->id());
674 scoped_ptr<OpenChannelParams> scoped_params(params);
675 lazy_background_task_queue_->AddPendingTask(
678 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
679 weak_factory_.GetWeakPtr(),
680 base::Passed(&scoped_params),
681 params->source->GetID()));
685 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params,
686 const std::string& tls_channel_id) {
687 params->tls_channel_id.assign(tls_channel_id);
688 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
690 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
691 pending_tls_channel_id_channels_.find(channel_id);
692 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
697 BrowserContext* context = params->source->GetBrowserContext();
699 const Extension* target_extension =
700 ExtensionSystem::Get(context)->extension_service()->extensions()->GetByID(
701 params->target_extension_id);
702 if (!target_extension) {
703 pending_tls_channel_id_channels_.erase(channel_id);
704 DispatchOnDisconnect(
705 params->source, params->receiver_port_id,
706 kReceivingEndDoesntExistError);
709 PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
710 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
711 context, target_extension, params.get())) {
712 // Lazy background queue took ownership. Release ours.
713 ignore_result(params.release());
714 // Messages queued up waiting for the TLS channel ID now need to be queued
715 // up for the lazy background page to load.
716 for (PendingMessagesQueue::iterator it = pending_messages.begin();
717 it != pending_messages.end();
719 EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
723 OpenChannelImpl(params.Pass());
724 // Messages queued up waiting for the TLS channel ID can be posted now.
725 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
726 if (channel_iter != channels_.end()) {
727 for (PendingMessagesQueue::iterator it = pending_messages.begin();
728 it != pending_messages.end();
730 DispatchMessage(it->first, channel_iter->second, it->second);
734 pending_tls_channel_id_channels_.erase(channel_id);
737 void MessageService::PendingLazyBackgroundPageOpenChannel(
738 scoped_ptr<OpenChannelParams> params,
739 int source_process_id,
740 ExtensionHost* host) {
742 return; // TODO(mpcomplete): notify source of disconnect?
744 // Re-lookup the source process since it may no longer be valid.
745 content::RenderProcessHost* source =
746 content::RenderProcessHost::FromID(source_process_id);
750 params->source = source;
751 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
753 params->target_extension_id));
754 OpenChannelImpl(params.Pass());
757 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
759 const std::string& error_message) {
760 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
761 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
764 } // namespace extensions