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/prefs/pref_service.h"
14 #include "base/stl_util.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/extensions/api/messaging/extension_message_port.h"
18 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
19 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
20 #include "chrome/browser/extensions/api/tabs/tabs_constants.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 "content/public/browser/notification_service.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/render_widget_host.h"
30 #include "content/public/browser/render_widget_host_view.h"
31 #include "content/public/browser/site_instance.h"
32 #include "content/public/browser/web_contents.h"
33 #include "extensions/browser/extension_host.h"
34 #include "extensions/browser/extension_system.h"
35 #include "extensions/browser/extensions_browser_client.h"
36 #include "extensions/browser/lazy_background_task_queue.h"
37 #include "extensions/browser/pref_names.h"
38 #include "extensions/browser/process_manager.h"
39 #include "extensions/common/extension.h"
40 #include "extensions/common/manifest_constants.h"
41 #include "extensions/common/manifest_handlers/background_info.h"
42 #include "extensions/common/manifest_handlers/externally_connectable.h"
43 #include "extensions/common/manifest_handlers/incognito_info.h"
44 #include "extensions/common/permissions/permissions_data.h"
45 #include "net/base/completion_callback.h"
48 using content::BrowserContext;
49 using content::SiteInstance;
50 using content::WebContents;
52 // Since we have 2 ports for every channel, we just index channels by half the
54 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
55 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
56 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
58 // Port1 is always even, port2 is always odd.
59 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
61 // Change even to odd and vice versa, to get the other side of a given channel.
62 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
64 namespace extensions {
66 MessageService::PolicyPermission MessageService::IsNativeMessagingHostAllowed(
67 const PrefService* pref_service,
68 const std::string& native_host_name) {
69 PolicyPermission allow_result = ALLOW_ALL;
70 if (pref_service->IsManagedPreference(
71 pref_names::kNativeMessagingUserLevelHosts)) {
72 if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts))
73 allow_result = ALLOW_SYSTEM_ONLY;
76 // All native messaging hosts are allowed if there is no blacklist.
77 if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist))
79 const base::ListValue* blacklist =
80 pref_service->GetList(pref_names::kNativeMessagingBlacklist);
84 // Check if the name or the wildcard is in the blacklist.
85 base::StringValue name_value(native_host_name);
86 base::StringValue wildcard_value("*");
87 if (blacklist->Find(name_value) == blacklist->end() &&
88 blacklist->Find(wildcard_value) == blacklist->end()) {
92 // The native messaging host is blacklisted. Check the whitelist.
93 if (pref_service->IsManagedPreference(
94 pref_names::kNativeMessagingWhitelist)) {
95 const base::ListValue* whitelist =
96 pref_service->GetList(pref_names::kNativeMessagingWhitelist);
97 if (whitelist && whitelist->Find(name_value) != whitelist->end())
104 const char kReceivingEndDoesntExistError[] =
105 "Could not establish connection. Receiving end does not exist.";
106 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
107 const char kMissingPermissionError[] =
108 "Access to native messaging requires nativeMessaging permission.";
109 const char kProhibitedByPoliciesError[] =
110 "Access to the native messaging host was disabled by the system "
114 struct MessageService::MessageChannel {
115 scoped_ptr<MessagePort> opener;
116 scoped_ptr<MessagePort> receiver;
119 struct MessageService::OpenChannelParams {
120 content::RenderProcessHost* source;
121 base::DictionaryValue source_tab;
122 scoped_ptr<MessagePort> receiver;
123 int receiver_port_id;
124 std::string source_extension_id;
125 std::string target_extension_id;
127 std::string channel_name;
128 bool include_tls_channel_id;
129 std::string tls_channel_id;
131 // Takes ownership of receiver.
132 OpenChannelParams(content::RenderProcessHost* source,
133 scoped_ptr<base::DictionaryValue> source_tab,
134 MessagePort* receiver,
135 int receiver_port_id,
136 const std::string& source_extension_id,
137 const std::string& target_extension_id,
138 const GURL& source_url,
139 const std::string& channel_name,
140 bool include_tls_channel_id)
143 receiver_port_id(receiver_port_id),
144 source_extension_id(source_extension_id),
145 target_extension_id(target_extension_id),
146 source_url(source_url),
147 channel_name(channel_name),
148 include_tls_channel_id(include_tls_channel_id) {
150 this->source_tab.Swap(source_tab.get());
154 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
159 static base::StaticAtomicSequenceNumber g_next_channel_id;
160 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
162 static content::RenderProcessHost* GetExtensionProcess(
163 BrowserContext* context,
164 const std::string& extension_id) {
165 SiteInstance* site_instance =
166 ProcessManager::Get(context)->GetSiteInstanceForURL(
167 Extension::GetBaseURLFromExtensionId(extension_id));
168 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
173 content::RenderProcessHost*
174 MessageService::MessagePort::GetRenderProcessHost() {
179 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
180 unsigned channel_id =
181 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
183 if (channel_id == 0) {
184 int overflow_count = g_channel_id_overflow_count.GetNext();
185 if (overflow_count > 0)
186 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
189 unsigned port1_id = channel_id * 2;
190 unsigned port2_id = channel_id * 2 + 1;
192 // Sanity checks to make sure our channel<->port converters are correct.
193 DCHECK(IS_OPENER_PORT_ID(port1_id));
194 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
195 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
196 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
197 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
198 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
199 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
205 MessageService::MessageService(BrowserContext* context)
206 : lazy_background_task_queue_(
207 ExtensionSystem::Get(context)->lazy_background_task_queue()),
208 weak_factory_(this) {
209 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
210 content::NotificationService::AllBrowserContextsAndSources());
211 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
212 content::NotificationService::AllBrowserContextsAndSources());
215 MessageService::~MessageService() {
216 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
220 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
221 g_factory = LAZY_INSTANCE_INITIALIZER;
224 BrowserContextKeyedAPIFactory<MessageService>*
225 MessageService::GetFactoryInstance() {
226 return g_factory.Pointer();
230 MessageService* MessageService::Get(BrowserContext* context) {
231 return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
234 void MessageService::OpenChannelToExtension(
235 int source_process_id, int source_routing_id, int receiver_port_id,
236 const std::string& source_extension_id,
237 const std::string& target_extension_id,
238 const GURL& source_url,
239 const std::string& channel_name,
240 bool include_tls_channel_id) {
241 content::RenderProcessHost* source =
242 content::RenderProcessHost::FromID(source_process_id);
245 BrowserContext* context = source->GetBrowserContext();
247 ExtensionSystem* extension_system = ExtensionSystem::Get(context);
248 DCHECK(extension_system);
249 const Extension* target_extension = extension_system->extension_service()->
250 extensions()->GetByID(target_extension_id);
251 if (!target_extension) {
252 DispatchOnDisconnect(
253 source, receiver_port_id, kReceivingEndDoesntExistError);
257 bool is_web_connection = false;
259 if (source_extension_id != target_extension_id) {
260 // It's an external connection. Check the externally_connectable manifest
261 // key if it's present. If it's not, we allow connection from any extension
263 ExternallyConnectableInfo* externally_connectable =
264 static_cast<ExternallyConnectableInfo*>(
265 target_extension->GetManifestData(
266 manifest_keys::kExternallyConnectable));
267 bool is_externally_connectable = false;
269 if (externally_connectable) {
270 if (source_extension_id.empty()) {
271 // No source extension ID so the source was a web page. Check that the
273 is_web_connection = true;
274 is_externally_connectable =
275 externally_connectable->matches.MatchesURL(source_url);
276 // Only include the TLS channel ID for externally connected web pages.
277 include_tls_channel_id &=
278 is_externally_connectable &&
279 externally_connectable->accepts_tls_channel_id;
281 // Source extension ID so the source was an extension. Check that the
282 // extension matches.
283 is_externally_connectable =
284 externally_connectable->IdCanConnect(source_extension_id);
287 // Default behaviour. Any extension, no webpages.
288 is_externally_connectable = !source_extension_id.empty();
291 if (!is_externally_connectable) {
292 // Important: use kReceivingEndDoesntExistError here so that we don't
293 // leak information about this extension to callers. This way it's
294 // indistinguishable from the extension just not existing.
295 DispatchOnDisconnect(
296 source, receiver_port_id, kReceivingEndDoesntExistError);
301 WebContents* source_contents = tab_util::GetWebContentsByID(
302 source_process_id, source_routing_id);
304 if (context->IsOffTheRecord() &&
305 !util::IsIncognitoEnabled(target_extension_id, context)) {
306 // Give the user a chance to accept an incognito connection from the web if
307 // they haven't already, with the conditions:
308 // - Only for spanning-mode incognito. We don't want the complication of
309 // spinning up an additional process here which might need to do some
310 // setup that we're not expecting.
311 // - Only for extensions that can't normally be enabled in incognito, since
312 // that surface (e.g. chrome://extensions) should be the only one for
313 // enabling in incognito. In practice this means platform apps only.
314 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
315 target_extension->can_be_incognito_enabled() ||
316 // This check may show a dialog.
317 !IncognitoConnectability::Get(context)
318 ->Query(target_extension, source_contents, source_url)) {
319 DispatchOnDisconnect(
320 source, receiver_port_id, kReceivingEndDoesntExistError);
325 // Note: we use the source's profile here. If the source is an incognito
326 // process, we will use the incognito EPM to find the right extension process,
327 // which depends on whether the extension uses spanning or split mode.
328 MessagePort* receiver = new ExtensionMessagePort(
329 GetExtensionProcess(context, target_extension_id),
331 target_extension_id);
333 // Include info about the opener's tab (if it was a tab).
334 scoped_ptr<base::DictionaryValue> source_tab;
335 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
336 // Only the tab id is useful to platform apps for internal use. The
337 // unnecessary bits will be stripped out in
338 // MessagingBindings::DispatchOnConnect().
339 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
342 OpenChannelParams* params = new OpenChannelParams(
343 source, source_tab.Pass(), receiver, receiver_port_id,
344 source_extension_id, target_extension_id, source_url, channel_name,
345 include_tls_channel_id);
347 // If the target requests the TLS channel id, begin the lookup for it.
348 // The target might also be a lazy background page, checked next, but the
349 // loading of lazy background pages continues asynchronously, so enqueue
350 // messages awaiting TLS channel ID first.
351 if (include_tls_channel_id) {
352 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
353 = PendingMessagesQueue();
354 property_provider_.GetChannelID(
355 Profile::FromBrowserContext(context),
357 base::Bind(&MessageService::GotChannelID,
358 weak_factory_.GetWeakPtr(),
359 base::Passed(make_scoped_ptr(params))));
363 // The target might be a lazy background page. In that case, we have to check
364 // if it is loaded and ready, and if not, queue up the task and load the
366 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
367 context, target_extension, params)) {
371 OpenChannelImpl(make_scoped_ptr(params));
374 void MessageService::OpenChannelToNativeApp(
375 int source_process_id,
376 int source_routing_id,
377 int receiver_port_id,
378 const std::string& source_extension_id,
379 const std::string& native_app_name) {
380 content::RenderProcessHost* source =
381 content::RenderProcessHost::FromID(source_process_id);
385 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
386 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
387 ExtensionService* extension_service =
388 ExtensionSystem::Get(profile)->extension_service();
389 bool has_permission = false;
390 if (extension_service) {
391 const Extension* extension =
392 extension_service->GetExtensionById(source_extension_id, false);
393 has_permission = extension &&
394 extension->permissions_data()->HasAPIPermission(
395 APIPermission::kNativeMessaging);
398 if (!has_permission) {
399 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
403 PrefService* pref_service = profile->GetPrefs();
405 // Verify that the host is not blocked by policies.
406 PolicyPermission policy_permission =
407 IsNativeMessagingHostAllowed(pref_service, native_app_name);
408 if (policy_permission == DISALLOW) {
409 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
413 scoped_ptr<MessageChannel> channel(new MessageChannel());
414 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
415 source_extension_id));
417 // Get handle of the native view and pass it to the native messaging host.
418 gfx::NativeView native_view =
419 content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
420 GetView()->GetNativeView();
422 std::string error = kReceivingEndDoesntExistError;
423 scoped_ptr<NativeMessageHost> native_host = NativeMessageHost::Create(
427 policy_permission == ALLOW_ALL,
430 // Abandon the channel.
431 if (!native_host.get()) {
432 LOG(ERROR) << "Failed to create native process.";
433 DispatchOnDisconnect(
434 source, receiver_port_id, error);
437 channel->receiver.reset(new NativeMessagePort(
438 weak_factory_.GetWeakPtr(), receiver_port_id, native_host.Pass()));
440 // Keep the opener alive until the channel is closed.
441 channel->opener->IncrementLazyKeepaliveCount();
443 AddChannel(channel.release(), receiver_port_id);
444 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
445 const char kNativeMessagingNotSupportedError[] =
446 "Native Messaging is not supported on this platform.";
447 DispatchOnDisconnect(
448 source, receiver_port_id, kNativeMessagingNotSupportedError);
449 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
452 void MessageService::OpenChannelToTab(
453 int source_process_id, int source_routing_id, int receiver_port_id,
454 int tab_id, const std::string& extension_id,
455 const std::string& channel_name) {
456 content::RenderProcessHost* source =
457 content::RenderProcessHost::FromID(source_process_id);
460 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
462 WebContents* contents = NULL;
463 scoped_ptr<MessagePort> receiver;
464 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
465 NULL, NULL, &contents, NULL)) {
466 receiver.reset(new ExtensionMessagePort(
467 contents->GetRenderProcessHost(),
468 contents->GetRenderViewHost()->GetRoutingID(),
472 if (contents && contents->GetController().NeedsReload()) {
473 // The tab isn't loaded yet. Don't attempt to connect.
474 DispatchOnDisconnect(
475 source, receiver_port_id, kReceivingEndDoesntExistError);
479 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
481 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
482 // for opening to tabs.
487 GURL(), // Source URL doesn't make sense for opening to tabs.
489 false)); // Connections to tabs don't get TLS channel IDs.
490 OpenChannelImpl(params.Pass());
493 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
495 return false; // Closed while in flight.
497 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
498 DispatchOnDisconnect(params->source,
499 params->receiver_port_id,
500 kReceivingEndDoesntExistError);
504 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
505 // http://code.google.com/p/chromium/issues/detail?id=19067
506 CHECK(params->receiver->GetRenderProcessHost());
508 MessageChannel* channel(new MessageChannel);
509 channel->opener.reset(new ExtensionMessagePort(params->source,
511 params->source_extension_id));
512 channel->receiver.reset(params->receiver.release());
514 CHECK(channel->receiver->GetRenderProcessHost());
516 AddChannel(channel, params->receiver_port_id);
518 CHECK(channel->receiver->GetRenderProcessHost());
520 // Send the connect event to the receiver. Give it the opener's port ID (the
521 // opener has the opposite port ID).
522 channel->receiver->DispatchOnConnect(params->receiver_port_id,
523 params->channel_name,
525 params->source_extension_id,
526 params->target_extension_id,
528 params->tls_channel_id);
530 // Keep both ends of the channel alive until the channel is closed.
531 channel->opener->IncrementLazyKeepaliveCount();
532 channel->receiver->IncrementLazyKeepaliveCount();
536 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
537 int channel_id = GET_CHANNEL_ID(receiver_port_id);
538 CHECK(channels_.find(channel_id) == channels_.end());
539 channels_[channel_id] = channel;
540 pending_lazy_background_page_channels_.erase(channel_id);
543 void MessageService::CloseChannel(int port_id,
544 const std::string& error_message) {
545 // Note: The channel might be gone already, if the other side closed first.
546 int channel_id = GET_CHANNEL_ID(port_id);
547 MessageChannelMap::iterator it = channels_.find(channel_id);
548 if (it == channels_.end()) {
549 PendingLazyBackgroundPageChannelMap::iterator pending =
550 pending_lazy_background_page_channels_.find(channel_id);
551 if (pending != pending_lazy_background_page_channels_.end()) {
552 lazy_background_task_queue_->AddPendingTask(
553 pending->second.first, pending->second.second,
554 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
555 weak_factory_.GetWeakPtr(), port_id, error_message));
559 CloseChannelImpl(it, port_id, error_message, true);
562 void MessageService::CloseChannelImpl(
563 MessageChannelMap::iterator channel_iter,
565 const std::string& error_message,
566 bool notify_other_port) {
567 MessageChannel* channel = channel_iter->second;
569 // Notify the other side.
570 if (notify_other_port) {
571 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
572 channel->receiver.get() : channel->opener.get();
573 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
577 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
578 channel->opener->DecrementLazyKeepaliveCount();
579 channel->receiver->DecrementLazyKeepaliveCount();
581 delete channel_iter->second;
582 channels_.erase(channel_iter);
585 void MessageService::PostMessage(int source_port_id, const Message& message) {
586 int channel_id = GET_CHANNEL_ID(source_port_id);
587 MessageChannelMap::iterator iter = channels_.find(channel_id);
588 if (iter == channels_.end()) {
589 // If this channel is pending, queue up the PostMessage to run once
590 // the channel opens.
591 EnqueuePendingMessage(source_port_id, channel_id, message);
595 DispatchMessage(source_port_id, iter->second, message);
598 void MessageService::Observe(int type,
599 const content::NotificationSource& source,
600 const content::NotificationDetails& details) {
602 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
603 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
604 content::RenderProcessHost* renderer =
605 content::Source<content::RenderProcessHost>(source).ptr();
606 OnProcessClosed(renderer);
615 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
616 // Close any channels that share this renderer. We notify the opposite
617 // port that his pair has closed.
618 for (MessageChannelMap::iterator it = channels_.begin();
619 it != channels_.end(); ) {
620 MessageChannelMap::iterator current = it++;
622 content::RenderProcessHost* opener_process =
623 current->second->opener->GetRenderProcessHost();
624 content::RenderProcessHost* receiver_process =
625 current->second->receiver->GetRenderProcessHost();
627 // Only notify the other side if it has a different porocess host.
628 bool notify_other_port = opener_process && receiver_process &&
629 opener_process != receiver_process;
631 if (opener_process == process) {
632 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
633 std::string(), notify_other_port);
634 } else if (receiver_process == process) {
635 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
636 std::string(), notify_other_port);
641 void MessageService::EnqueuePendingMessage(int source_port_id,
643 const Message& message) {
644 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
645 pending_tls_channel_id_channels_.find(channel_id);
646 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
647 pending_for_tls_channel_id->second.push_back(
648 PendingMessage(source_port_id, message));
649 // Pending messages must only be pending the TLS channel ID or lazy
650 // background page loading, never both.
653 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
658 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
661 const Message& message) {
662 PendingLazyBackgroundPageChannelMap::iterator pending =
663 pending_lazy_background_page_channels_.find(channel_id);
664 if (pending != pending_lazy_background_page_channels_.end()) {
665 lazy_background_task_queue_->AddPendingTask(
666 pending->second.first, pending->second.second,
667 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
668 weak_factory_.GetWeakPtr(), source_port_id, message));
672 void MessageService::DispatchMessage(int source_port_id,
673 MessageChannel* channel,
674 const Message& message) {
675 // Figure out which port the ID corresponds to.
676 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
677 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
678 channel->opener.get() : channel->receiver.get();
680 port->DispatchOnMessage(message, dest_port_id);
683 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
684 BrowserContext* context,
685 const Extension* extension,
686 OpenChannelParams* params) {
687 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
690 // If the extension uses spanning incognito mode, make sure we're always
691 // using the original profile since that is what the extension process
693 if (!IncognitoInfo::IsSplitMode(extension))
694 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
696 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
699 pending_lazy_background_page_channels_
700 [GET_CHANNEL_ID(params->receiver_port_id)] =
701 PendingLazyBackgroundPageChannel(context, extension->id());
702 scoped_ptr<OpenChannelParams> scoped_params(params);
703 lazy_background_task_queue_->AddPendingTask(
706 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
707 weak_factory_.GetWeakPtr(),
708 base::Passed(&scoped_params),
709 params->source->GetID()));
713 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params,
714 const std::string& tls_channel_id) {
715 params->tls_channel_id.assign(tls_channel_id);
716 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
718 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
719 pending_tls_channel_id_channels_.find(channel_id);
720 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
725 BrowserContext* context = params->source->GetBrowserContext();
727 const Extension* target_extension =
728 ExtensionSystem::Get(context)->extension_service()->extensions()->GetByID(
729 params->target_extension_id);
730 if (!target_extension) {
731 pending_tls_channel_id_channels_.erase(channel_id);
732 DispatchOnDisconnect(
733 params->source, params->receiver_port_id,
734 kReceivingEndDoesntExistError);
737 PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
738 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
739 context, target_extension, params.get())) {
740 // Lazy background queue took ownership. Release ours.
741 ignore_result(params.release());
742 // Messages queued up waiting for the TLS channel ID now need to be queued
743 // up for the lazy background page to load.
744 for (PendingMessagesQueue::iterator it = pending_messages.begin();
745 it != pending_messages.end();
747 EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
751 OpenChannelImpl(params.Pass());
752 // Messages queued up waiting for the TLS channel ID can be posted now.
753 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
754 if (channel_iter != channels_.end()) {
755 for (PendingMessagesQueue::iterator it = pending_messages.begin();
756 it != pending_messages.end();
758 DispatchMessage(it->first, channel_iter->second, it->second);
762 pending_tls_channel_id_channels_.erase(channel_id);
765 void MessageService::PendingLazyBackgroundPageOpenChannel(
766 scoped_ptr<OpenChannelParams> params,
767 int source_process_id,
768 ExtensionHost* host) {
770 return; // TODO(mpcomplete): notify source of disconnect?
772 // Re-lookup the source process since it may no longer be valid.
773 content::RenderProcessHost* source =
774 content::RenderProcessHost::FromID(source_process_id);
778 params->source = source;
779 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
781 params->target_extension_id));
782 OpenChannelImpl(params.Pass());
785 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
787 const std::string& error_message) {
788 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
789 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
792 } // namespace extensions