Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / messaging / message_service.cc
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.
4
5 #include "chrome/browser/extensions/api/messaging/message_service.h"
6
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.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"
43 #include "url/gurl.h"
44
45 using content::SiteInstance;
46 using content::WebContents;
47
48 // Since we have 2 ports for every channel, we just index channels by half the
49 // port ID.
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)
53
54 // Port1 is always even, port2 is always odd.
55 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
56
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)
59
60 namespace extensions {
61
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 "
69     "administrator.";
70 #endif
71
72 struct MessageService::MessageChannel {
73   scoped_ptr<MessagePort> opener;
74   scoped_ptr<MessagePort> receiver;
75 };
76
77 struct MessageService::OpenChannelParams {
78   content::RenderProcessHost* source;
79   base::DictionaryValue source_tab;
80   scoped_ptr<MessagePort> receiver;
81   int receiver_port_id;
82   std::string source_extension_id;
83   std::string target_extension_id;
84   GURL source_url;
85   std::string channel_name;
86   bool include_tls_channel_id;
87   std::string tls_channel_id;
88
89   // Takes ownership of receiver.
90   OpenChannelParams(content::RenderProcessHost* source,
91                     scoped_ptr<base::DictionaryValue> source_tab,
92                     MessagePort* receiver,
93                     int receiver_port_id,
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)
99       : source(source),
100         receiver(receiver),
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) {
107     if (source_tab)
108       this->source_tab.Swap(source_tab.get());
109   }
110
111  private:
112   DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
113 };
114
115 namespace {
116
117 static base::StaticAtomicSequenceNumber g_next_channel_id;
118 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
119
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;
126 }
127
128 }  // namespace
129
130 content::RenderProcessHost*
131     MessageService::MessagePort::GetRenderProcessHost() {
132   return NULL;
133 }
134
135 // static
136 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
137   unsigned channel_id =
138       static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
139
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);
144   }
145
146   unsigned port1_id = channel_id * 2;
147   unsigned port2_id = channel_id * 2 + 1;
148
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);
157
158   *port1 = port1_id;
159   *port2 = port2_id;
160 }
161
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());
170 }
171
172 MessageService::~MessageService() {
173   STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
174   channels_.clear();
175 }
176
177 static base::LazyInstance<ProfileKeyedAPIFactory<MessageService> >
178 g_factory = LAZY_INSTANCE_INITIALIZER;
179
180 // static
181 ProfileKeyedAPIFactory<MessageService>* MessageService::GetFactoryInstance() {
182   return g_factory.Pointer();
183 }
184
185 // static
186 MessageService* MessageService::Get(content::BrowserContext* context) {
187   Profile* profile = Profile::FromBrowserContext(context);
188   return ProfileKeyedAPIFactory<MessageService>::GetForProfile(profile);
189 }
190
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);
200   if (!source)
201     return;
202   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
203
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);
211     return;
212   }
213
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);
220     return;
221   }
222
223   bool is_web_connection = false;
224
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
228     // but not webpages.
229     ExternallyConnectableInfo* externally_connectable =
230         static_cast<ExternallyConnectableInfo*>(
231             target_extension->GetManifestData(
232                 manifest_keys::kExternallyConnectable));
233     bool is_externally_connectable = false;
234
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
238         // URL matches.
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;
246       } else {
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);
251       }
252     } else {
253       // Default behaviour. Any extension, no webpages.
254       is_externally_connectable = !source_extension_id.empty();
255     }
256
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);
263       return;
264     }
265   }
266
267   WebContents* source_contents = tab_util::GetWebContentsByID(
268       source_process_id, source_routing_id);
269
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,
279                                                       source_contents,
280                                                       source_url)) {
281       DispatchOnDisconnect(
282           source, receiver_port_id, kReceivingEndDoesntExistError);
283       return;
284     }
285   }
286
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);
293
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;
297
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;
304   }
305
306   OpenChannelParams* params = new OpenChannelParams(source,
307                                                     source_tab.Pass(),
308                                                     receiver,
309                                                     receiver_port_id,
310                                                     source_extension_id,
311                                                     target_extension_id,
312                                                     source_url_for_tab,
313                                                     channel_name,
314                                                     include_tls_channel_id);
315
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(
324         profile,
325         source_url,
326         base::Bind(&MessageService::GotDomainBoundCert,
327                    weak_factory_.GetWeakPtr(),
328                    base::Passed(make_scoped_ptr(params))));
329     return;
330   }
331
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
334   // page.
335   if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile,
336                                                        target_extension,
337                                                        params)) {
338     return;
339   }
340
341   OpenChannelImpl(make_scoped_ptr(params));
342 }
343
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);
352   if (!source)
353     return;
354
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);
365   }
366
367   if (!has_permission) {
368     DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
369     return;
370   }
371
372   PrefService* pref_service = profile->GetPrefs();
373
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);
379     return;
380   }
381
382   scoped_ptr<MessageChannel> channel(new MessageChannel());
383   channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
384                                                  source_extension_id));
385
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();
390
391   scoped_ptr<NativeMessageProcessHost> native_process =
392       NativeMessageProcessHost::Create(
393           native_view,
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);
398
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);
404     return;
405   }
406   channel->receiver.reset(new NativeMessagePort(native_process.release()));
407
408   // Keep the opener alive until the channel is closed.
409   channel->opener->IncrementLazyKeepaliveCount();
410
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))
418 }
419
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);
426   if (!source)
427     return;
428   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
429
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(),
437         extension_id));
438   }
439
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);
444     return;
445   }
446
447   scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
448         source,
449         scoped_ptr<base::DictionaryValue>(),  // Source tab doesn't make sense
450                                               // for opening to tabs.
451         receiver.release(),
452         receiver_port_id,
453         extension_id,
454         extension_id,
455         GURL(),  // Source URL doesn't make sense for opening to tabs.
456         channel_name,
457         false));  // Connections to tabs don't get TLS channel IDs.
458   OpenChannelImpl(params.Pass());
459 }
460
461 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
462   if (!params->source)
463     return false;  // Closed while in flight.
464
465   if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
466     DispatchOnDisconnect(params->source,
467                          params->receiver_port_id,
468                          kReceivingEndDoesntExistError);
469     return false;
470   }
471
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());
475
476   MessageChannel* channel(new MessageChannel);
477   channel->opener.reset(new ExtensionMessagePort(params->source,
478                                                  MSG_ROUTING_CONTROL,
479                                                  params->source_extension_id));
480   channel->receiver.reset(params->receiver.release());
481
482   CHECK(channel->receiver->GetRenderProcessHost());
483
484   AddChannel(channel, params->receiver_port_id);
485
486   CHECK(channel->receiver->GetRenderProcessHost());
487
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,
492                                        params->source_tab,
493                                        params->source_extension_id,
494                                        params->target_extension_id,
495                                        params->source_url,
496                                        params->tls_channel_id);
497
498   // Keep both ends of the channel alive until the channel is closed.
499   channel->opener->IncrementLazyKeepaliveCount();
500   channel->receiver->IncrementLazyKeepaliveCount();
501   return true;
502 }
503
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);
509 }
510
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));
524     }
525     return;
526   }
527   CloseChannelImpl(it, port_id, error_message, true);
528 }
529
530 void MessageService::CloseChannelImpl(
531     MessageChannelMap::iterator channel_iter,
532     int closing_port_id,
533     const std::string& error_message,
534     bool notify_other_port) {
535   MessageChannel* channel = channel_iter->second;
536
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),
542                                error_message);
543   }
544
545   // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
546   channel->opener->DecrementLazyKeepaliveCount();
547   channel->receiver->DecrementLazyKeepaliveCount();
548
549   delete channel_iter->second;
550   channels_.erase(channel_iter);
551 }
552
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);
560     return;
561   }
562
563   DispatchMessage(source_port_id, iter->second, message);
564 }
565
566 void MessageService::PostMessageFromNativeProcess(int port_id,
567                                                   const std::string& message) {
568   PostMessage(port_id, Message(message, false /* user_gesture */));
569 }
570
571 void MessageService::Observe(int type,
572                              const content::NotificationSource& source,
573                              const content::NotificationDetails& details) {
574   switch (type) {
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);
580       break;
581     }
582     default:
583       NOTREACHED();
584       return;
585   }
586 }
587
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++;
594
595     content::RenderProcessHost* opener_process =
596         current->second->opener->GetRenderProcessHost();
597     content::RenderProcessHost* receiver_process =
598         current->second->receiver->GetRenderProcessHost();
599
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;
603
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);
610     }
611   }
612 }
613
614 void MessageService::EnqueuePendingMessage(int source_port_id,
615                                            int channel_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.
624     return;
625   }
626   EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
627                                              channel_id,
628                                              message);
629 }
630
631 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
632     int source_port_id,
633     int channel_id,
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));
642   }
643 }
644
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();
652
653   port->DispatchOnMessage(message, dest_port_id);
654 }
655
656 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
657     Profile* profile,
658     const Extension* extension,
659     OpenChannelParams* params) {
660   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
661     return false;
662
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
665   // will use.
666   if (!IncognitoInfo::IsSplitMode(extension))
667     profile = profile->GetOriginalProfile();
668
669   if (!lazy_background_task_queue_->ShouldEnqueueTask(profile, extension))
670     return false;
671
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()));
680   return true;
681 }
682
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);
687
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()) {
691     NOTREACHED();
692     return;
693   }
694
695   Profile* profile = Profile::FromBrowserContext(
696       params->source->GetBrowserContext());
697
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);
705     return;
706   }
707   PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
708   if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(profile,
709                                                        target_extension,
710                                                        params.get())) {
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();
717          it++) {
718       EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
719                                                  it->second);
720     }
721   } else {
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();
728            it++) {
729         DispatchMessage(it->first, channel_iter->second, it->second);
730       }
731     }
732   }
733   pending_tls_channel_id_channels_.erase(channel_id);
734 }
735
736 void MessageService::PendingLazyBackgroundPageOpenChannel(
737     scoped_ptr<OpenChannelParams> params,
738     int source_process_id,
739     ExtensionHost* host) {
740   if (!host)
741     return;  // TODO(mpcomplete): notify source of disconnect?
742
743   // Re-lookup the source process since it may no longer be valid.
744   content::RenderProcessHost* source =
745       content::RenderProcessHost::FromID(source_process_id);
746   if (!source)
747     return;
748
749   params->source = source;
750   params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
751                                                   MSG_ROUTING_CONTROL,
752                                                   params->target_extension_id));
753   OpenChannelImpl(params.Pass());
754 }
755
756 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
757                                           int port_id,
758                                           const std::string& error_message) {
759   ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
760   port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
761 }
762
763 }  // namespace extensions