Upstream version 8.37.180.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_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/extension_util.h"
35 #include "extensions/browser/extensions_browser_client.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/extension_messages.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"
46 #include "url/gurl.h"
47
48 using content::BrowserContext;
49 using content::SiteInstance;
50 using content::WebContents;
51
52 // Since we have 2 ports for every channel, we just index channels by half the
53 // port ID.
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)
57
58 // Port1 is always even, port2 is always odd.
59 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
60
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)
63
64 namespace extensions {
65
66 const char kReceivingEndDoesntExistError[] =
67     "Could not establish connection. Receiving end does not exist.";
68 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
69 const char kMissingPermissionError[] =
70     "Access to native messaging requires nativeMessaging permission.";
71 const char kProhibitedByPoliciesError[] =
72     "Access to the native messaging host was disabled by the system "
73     "administrator.";
74 #endif
75
76 struct MessageService::MessageChannel {
77   scoped_ptr<MessagePort> opener;
78   scoped_ptr<MessagePort> receiver;
79 };
80
81 struct MessageService::OpenChannelParams {
82   content::RenderProcessHost* source;
83   base::DictionaryValue source_tab;
84   scoped_ptr<MessagePort> receiver;
85   int receiver_port_id;
86   std::string source_extension_id;
87   std::string target_extension_id;
88   GURL source_url;
89   std::string channel_name;
90   bool include_tls_channel_id;
91   std::string tls_channel_id;
92
93   // Takes ownership of receiver.
94   OpenChannelParams(content::RenderProcessHost* source,
95                     scoped_ptr<base::DictionaryValue> source_tab,
96                     MessagePort* receiver,
97                     int receiver_port_id,
98                     const std::string& source_extension_id,
99                     const std::string& target_extension_id,
100                     const GURL& source_url,
101                     const std::string& channel_name,
102                     bool include_tls_channel_id)
103       : source(source),
104         receiver(receiver),
105         receiver_port_id(receiver_port_id),
106         source_extension_id(source_extension_id),
107         target_extension_id(target_extension_id),
108         source_url(source_url),
109         channel_name(channel_name),
110         include_tls_channel_id(include_tls_channel_id) {
111     if (source_tab)
112       this->source_tab.Swap(source_tab.get());
113   }
114
115  private:
116   DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
117 };
118
119 namespace {
120
121 static base::StaticAtomicSequenceNumber g_next_channel_id;
122 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
123
124 static content::RenderProcessHost* GetExtensionProcess(
125     BrowserContext* context,
126     const std::string& extension_id) {
127   SiteInstance* site_instance =
128       ExtensionSystem::Get(context)->process_manager()->GetSiteInstanceForURL(
129           Extension::GetBaseURLFromExtensionId(extension_id));
130   return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
131 }
132
133 }  // namespace
134
135 content::RenderProcessHost*
136     MessageService::MessagePort::GetRenderProcessHost() {
137   return NULL;
138 }
139
140 // static
141 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
142   unsigned channel_id =
143       static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
144
145   if (channel_id == 0) {
146     int overflow_count = g_channel_id_overflow_count.GetNext();
147     if (overflow_count > 0)
148       UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
149   }
150
151   unsigned port1_id = channel_id * 2;
152   unsigned port2_id = channel_id * 2 + 1;
153
154   // Sanity checks to make sure our channel<->port converters are correct.
155   DCHECK(IS_OPENER_PORT_ID(port1_id));
156   DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
157   DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
158   DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
159   DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
160   DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
161   DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
162
163   *port1 = port1_id;
164   *port2 = port2_id;
165 }
166
167 MessageService::MessageService(BrowserContext* context)
168     : lazy_background_task_queue_(
169           ExtensionSystem::Get(context)->lazy_background_task_queue()),
170       weak_factory_(this) {
171   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
172                  content::NotificationService::AllBrowserContextsAndSources());
173   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
174                  content::NotificationService::AllBrowserContextsAndSources());
175 }
176
177 MessageService::~MessageService() {
178   STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
179   channels_.clear();
180 }
181
182 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
183     g_factory = LAZY_INSTANCE_INITIALIZER;
184
185 // static
186 BrowserContextKeyedAPIFactory<MessageService>*
187 MessageService::GetFactoryInstance() {
188   return g_factory.Pointer();
189 }
190
191 // static
192 MessageService* MessageService::Get(BrowserContext* context) {
193   return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
194 }
195
196 void MessageService::OpenChannelToExtension(
197     int source_process_id, int source_routing_id, int receiver_port_id,
198     const std::string& source_extension_id,
199     const std::string& target_extension_id,
200     const GURL& source_url,
201     const std::string& channel_name,
202     bool include_tls_channel_id) {
203   content::RenderProcessHost* source =
204       content::RenderProcessHost::FromID(source_process_id);
205   if (!source)
206     return;
207   BrowserContext* context = source->GetBrowserContext();
208
209   ExtensionSystem* extension_system = ExtensionSystem::Get(context);
210   DCHECK(extension_system);
211   const Extension* target_extension = extension_system->extension_service()->
212       extensions()->GetByID(target_extension_id);
213   if (!target_extension) {
214     DispatchOnDisconnect(
215         source, receiver_port_id, kReceivingEndDoesntExistError);
216     return;
217   }
218
219   // Only running ephemeral apps can receive messages. Idle cached ephemeral
220   // apps are invisible and should not be connectable.
221   if (util::IsEphemeralApp(target_extension_id, context) &&
222       util::IsExtensionIdle(target_extension_id, context)) {
223     DispatchOnDisconnect(
224         source, receiver_port_id, kReceivingEndDoesntExistError);
225     return;
226   }
227
228   bool is_web_connection = false;
229
230   if (source_extension_id != target_extension_id) {
231     // It's an external connection. Check the externally_connectable manifest
232     // key if it's present. If it's not, we allow connection from any extension
233     // but not webpages.
234     ExternallyConnectableInfo* externally_connectable =
235         static_cast<ExternallyConnectableInfo*>(
236             target_extension->GetManifestData(
237                 manifest_keys::kExternallyConnectable));
238     bool is_externally_connectable = false;
239
240     if (externally_connectable) {
241       if (source_extension_id.empty()) {
242         // No source extension ID so the source was a web page. Check that the
243         // URL matches.
244         is_web_connection = true;
245         is_externally_connectable =
246             externally_connectable->matches.MatchesURL(source_url);
247         // Only include the TLS channel ID for externally connected web pages.
248         include_tls_channel_id &=
249             is_externally_connectable &&
250             externally_connectable->accepts_tls_channel_id;
251       } else {
252         // Source extension ID so the source was an extension. Check that the
253         // extension matches.
254         is_externally_connectable =
255             externally_connectable->IdCanConnect(source_extension_id);
256       }
257     } else {
258       // Default behaviour. Any extension, no webpages.
259       is_externally_connectable = !source_extension_id.empty();
260     }
261
262     if (!is_externally_connectable) {
263       // Important: use kReceivingEndDoesntExistError here so that we don't
264       // leak information about this extension to callers. This way it's
265       // indistinguishable from the extension just not existing.
266       DispatchOnDisconnect(
267           source, receiver_port_id, kReceivingEndDoesntExistError);
268       return;
269     }
270   }
271
272   WebContents* source_contents = tab_util::GetWebContentsByID(
273       source_process_id, source_routing_id);
274
275   if (context->IsOffTheRecord() &&
276       !util::IsIncognitoEnabled(target_extension_id, context)) {
277     // Give the user a chance to accept an incognito connection from the web if
278     // they haven't already, with the conditions:
279     // - Only for spanning-mode incognito. We don't want the complication of
280     //   spinning up an additional process here which might need to do some
281     //   setup that we're not expecting.
282     // - Only for extensions that can't normally be enabled in incognito, since
283     //   that surface (e.g. chrome://extensions) should be the only one for
284     //   enabling in incognito. In practice this means platform apps only.
285     if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
286         target_extension->can_be_incognito_enabled() ||
287         // This check may show a dialog.
288         !IncognitoConnectability::Get(context)
289              ->Query(target_extension, source_contents, source_url)) {
290       DispatchOnDisconnect(
291           source, receiver_port_id, kReceivingEndDoesntExistError);
292       return;
293     }
294   }
295
296   // Note: we use the source's profile here. If the source is an incognito
297   // process, we will use the incognito EPM to find the right extension process,
298   // which depends on whether the extension uses spanning or split mode.
299   MessagePort* receiver = new ExtensionMessagePort(
300       GetExtensionProcess(context, target_extension_id),
301       MSG_ROUTING_CONTROL,
302       target_extension_id);
303
304   // Include info about the opener's tab (if it was a tab).
305   scoped_ptr<base::DictionaryValue> source_tab;
306   GURL source_url_for_tab;
307
308   if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
309     // Only the tab id is useful to platform apps for internal use. The
310     // unnecessary bits will be stripped out in
311     // MessagingBindings::DispatchOnConnect().
312     source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
313     source_url_for_tab = source_url;
314   }
315
316   OpenChannelParams* params = new OpenChannelParams(source,
317                                                     source_tab.Pass(),
318                                                     receiver,
319                                                     receiver_port_id,
320                                                     source_extension_id,
321                                                     target_extension_id,
322                                                     source_url_for_tab,
323                                                     channel_name,
324                                                     include_tls_channel_id);
325
326   // If the target requests the TLS channel id, begin the lookup for it.
327   // The target might also be a lazy background page, checked next, but the
328   // loading of lazy background pages continues asynchronously, so enqueue
329   // messages awaiting TLS channel ID first.
330   if (include_tls_channel_id) {
331     pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
332         = PendingMessagesQueue();
333     property_provider_.GetDomainBoundCert(
334         Profile::FromBrowserContext(context),
335         source_url,
336         base::Bind(&MessageService::GotDomainBoundCert,
337                    weak_factory_.GetWeakPtr(),
338                    base::Passed(make_scoped_ptr(params))));
339     return;
340   }
341
342   // The target might be a lazy background page. In that case, we have to check
343   // if it is loaded and ready, and if not, queue up the task and load the
344   // page.
345   if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
346           context, target_extension, params)) {
347     return;
348   }
349
350   OpenChannelImpl(make_scoped_ptr(params));
351 }
352
353 void MessageService::OpenChannelToNativeApp(
354     int source_process_id,
355     int source_routing_id,
356     int receiver_port_id,
357     const std::string& source_extension_id,
358     const std::string& native_app_name) {
359   content::RenderProcessHost* source =
360       content::RenderProcessHost::FromID(source_process_id);
361   if (!source)
362     return;
363
364 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
365   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
366   ExtensionService* extension_service =
367       ExtensionSystem::Get(profile)->extension_service();
368   bool has_permission = false;
369   if (extension_service) {
370     const Extension* extension =
371         extension_service->GetExtensionById(source_extension_id, false);
372     has_permission = extension &&
373                      extension->permissions_data()->HasAPIPermission(
374                          APIPermission::kNativeMessaging);
375   }
376
377   if (!has_permission) {
378     DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
379     return;
380   }
381
382   PrefService* pref_service = profile->GetPrefs();
383
384   // Verify that the host is not blocked by policies.
385   NativeMessageProcessHost::PolicyPermission policy_permission =
386       NativeMessageProcessHost::IsHostAllowed(pref_service, native_app_name);
387   if (policy_permission == NativeMessageProcessHost::DISALLOW) {
388     DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
389     return;
390   }
391
392   scoped_ptr<MessageChannel> channel(new MessageChannel());
393   channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
394                                                  source_extension_id));
395
396   // Get handle of the native view and pass it to the native messaging host.
397   gfx::NativeView native_view =
398       content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
399           GetView()->GetNativeView();
400
401   scoped_ptr<NativeMessageProcessHost> native_process =
402       NativeMessageProcessHost::Create(
403           native_view,
404           base::WeakPtr<NativeMessageProcessHost::Client>(
405               weak_factory_.GetWeakPtr()),
406           source_extension_id, native_app_name, receiver_port_id,
407           policy_permission == NativeMessageProcessHost::ALLOW_ALL);
408
409   // Abandon the channel.
410   if (!native_process.get()) {
411     LOG(ERROR) << "Failed to create native process.";
412     DispatchOnDisconnect(
413         source, receiver_port_id, kReceivingEndDoesntExistError);
414     return;
415   }
416   channel->receiver.reset(new NativeMessagePort(native_process.release()));
417
418   // Keep the opener alive until the channel is closed.
419   channel->opener->IncrementLazyKeepaliveCount();
420
421   AddChannel(channel.release(), receiver_port_id);
422 #else  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
423   const char kNativeMessagingNotSupportedError[] =
424       "Native Messaging is not supported on this platform.";
425   DispatchOnDisconnect(
426       source, receiver_port_id, kNativeMessagingNotSupportedError);
427 #endif  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
428 }
429
430 void MessageService::OpenChannelToTab(
431     int source_process_id, int source_routing_id, int receiver_port_id,
432     int tab_id, const std::string& extension_id,
433     const std::string& channel_name) {
434   content::RenderProcessHost* source =
435       content::RenderProcessHost::FromID(source_process_id);
436   if (!source)
437     return;
438   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
439
440   WebContents* contents = NULL;
441   scoped_ptr<MessagePort> receiver;
442   if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
443                                    NULL, NULL, &contents, NULL)) {
444     receiver.reset(new ExtensionMessagePort(
445         contents->GetRenderProcessHost(),
446         contents->GetRenderViewHost()->GetRoutingID(),
447         extension_id));
448   }
449
450   if (contents && contents->GetController().NeedsReload()) {
451     // The tab isn't loaded yet. Don't attempt to connect.
452     DispatchOnDisconnect(
453         source, receiver_port_id, kReceivingEndDoesntExistError);
454     return;
455   }
456
457   scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
458         source,
459         scoped_ptr<base::DictionaryValue>(),  // Source tab doesn't make sense
460                                               // for opening to tabs.
461         receiver.release(),
462         receiver_port_id,
463         extension_id,
464         extension_id,
465         GURL(),  // Source URL doesn't make sense for opening to tabs.
466         channel_name,
467         false));  // Connections to tabs don't get TLS channel IDs.
468   OpenChannelImpl(params.Pass());
469 }
470
471 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
472   if (!params->source)
473     return false;  // Closed while in flight.
474
475   if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
476     DispatchOnDisconnect(params->source,
477                          params->receiver_port_id,
478                          kReceivingEndDoesntExistError);
479     return false;
480   }
481
482   // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
483   // http://code.google.com/p/chromium/issues/detail?id=19067
484   CHECK(params->receiver->GetRenderProcessHost());
485
486   MessageChannel* channel(new MessageChannel);
487   channel->opener.reset(new ExtensionMessagePort(params->source,
488                                                  MSG_ROUTING_CONTROL,
489                                                  params->source_extension_id));
490   channel->receiver.reset(params->receiver.release());
491
492   CHECK(channel->receiver->GetRenderProcessHost());
493
494   AddChannel(channel, params->receiver_port_id);
495
496   CHECK(channel->receiver->GetRenderProcessHost());
497
498   // Send the connect event to the receiver.  Give it the opener's port ID (the
499   // opener has the opposite port ID).
500   channel->receiver->DispatchOnConnect(params->receiver_port_id,
501                                        params->channel_name,
502                                        params->source_tab,
503                                        params->source_extension_id,
504                                        params->target_extension_id,
505                                        params->source_url,
506                                        params->tls_channel_id);
507
508   // Keep both ends of the channel alive until the channel is closed.
509   channel->opener->IncrementLazyKeepaliveCount();
510   channel->receiver->IncrementLazyKeepaliveCount();
511   return true;
512 }
513
514 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
515   int channel_id = GET_CHANNEL_ID(receiver_port_id);
516   CHECK(channels_.find(channel_id) == channels_.end());
517   channels_[channel_id] = channel;
518   pending_lazy_background_page_channels_.erase(channel_id);
519 }
520
521 void MessageService::CloseChannel(int port_id,
522                                   const std::string& error_message) {
523   // Note: The channel might be gone already, if the other side closed first.
524   int channel_id = GET_CHANNEL_ID(port_id);
525   MessageChannelMap::iterator it = channels_.find(channel_id);
526   if (it == channels_.end()) {
527     PendingLazyBackgroundPageChannelMap::iterator pending =
528         pending_lazy_background_page_channels_.find(channel_id);
529     if (pending != pending_lazy_background_page_channels_.end()) {
530       lazy_background_task_queue_->AddPendingTask(
531           pending->second.first, pending->second.second,
532           base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
533                      weak_factory_.GetWeakPtr(), port_id, error_message));
534     }
535     return;
536   }
537   CloseChannelImpl(it, port_id, error_message, true);
538 }
539
540 void MessageService::CloseChannelImpl(
541     MessageChannelMap::iterator channel_iter,
542     int closing_port_id,
543     const std::string& error_message,
544     bool notify_other_port) {
545   MessageChannel* channel = channel_iter->second;
546
547   // Notify the other side.
548   if (notify_other_port) {
549     MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
550         channel->receiver.get() : channel->opener.get();
551     port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
552                                error_message);
553   }
554
555   // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
556   channel->opener->DecrementLazyKeepaliveCount();
557   channel->receiver->DecrementLazyKeepaliveCount();
558
559   delete channel_iter->second;
560   channels_.erase(channel_iter);
561 }
562
563 void MessageService::PostMessage(int source_port_id, const Message& message) {
564   int channel_id = GET_CHANNEL_ID(source_port_id);
565   MessageChannelMap::iterator iter = channels_.find(channel_id);
566   if (iter == channels_.end()) {
567     // If this channel is pending, queue up the PostMessage to run once
568     // the channel opens.
569     EnqueuePendingMessage(source_port_id, channel_id, message);
570     return;
571   }
572
573   DispatchMessage(source_port_id, iter->second, message);
574 }
575
576 void MessageService::PostMessageFromNativeProcess(int port_id,
577                                                   const std::string& message) {
578   PostMessage(port_id, Message(message, false /* user_gesture */));
579 }
580
581 void MessageService::Observe(int type,
582                              const content::NotificationSource& source,
583                              const content::NotificationDetails& details) {
584   switch (type) {
585     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
586     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
587       content::RenderProcessHost* renderer =
588           content::Source<content::RenderProcessHost>(source).ptr();
589       OnProcessClosed(renderer);
590       break;
591     }
592     default:
593       NOTREACHED();
594       return;
595   }
596 }
597
598 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
599   // Close any channels that share this renderer.  We notify the opposite
600   // port that his pair has closed.
601   for (MessageChannelMap::iterator it = channels_.begin();
602        it != channels_.end(); ) {
603     MessageChannelMap::iterator current = it++;
604
605     content::RenderProcessHost* opener_process =
606         current->second->opener->GetRenderProcessHost();
607     content::RenderProcessHost* receiver_process =
608         current->second->receiver->GetRenderProcessHost();
609
610     // Only notify the other side if it has a different porocess host.
611     bool notify_other_port = opener_process && receiver_process &&
612         opener_process != receiver_process;
613
614     if (opener_process == process) {
615       CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
616                        std::string(), notify_other_port);
617     } else if (receiver_process == process) {
618       CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
619                        std::string(), notify_other_port);
620     }
621   }
622 }
623
624 void MessageService::EnqueuePendingMessage(int source_port_id,
625                                            int channel_id,
626                                            const Message& message) {
627   PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
628       pending_tls_channel_id_channels_.find(channel_id);
629   if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
630     pending_for_tls_channel_id->second.push_back(
631         PendingMessage(source_port_id, message));
632     // Pending messages must only be pending the TLS channel ID or lazy
633     // background page loading, never both.
634     return;
635   }
636   EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
637                                              channel_id,
638                                              message);
639 }
640
641 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
642     int source_port_id,
643     int channel_id,
644     const Message& message) {
645   PendingLazyBackgroundPageChannelMap::iterator pending =
646       pending_lazy_background_page_channels_.find(channel_id);
647   if (pending != pending_lazy_background_page_channels_.end()) {
648     lazy_background_task_queue_->AddPendingTask(
649         pending->second.first, pending->second.second,
650         base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
651                    weak_factory_.GetWeakPtr(), source_port_id, message));
652   }
653 }
654
655 void MessageService::DispatchMessage(int source_port_id,
656                                      MessageChannel* channel,
657                                      const Message& message) {
658   // Figure out which port the ID corresponds to.
659   int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
660   MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
661       channel->opener.get() : channel->receiver.get();
662
663   port->DispatchOnMessage(message, dest_port_id);
664 }
665
666 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
667     BrowserContext* context,
668     const Extension* extension,
669     OpenChannelParams* params) {
670   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
671     return false;
672
673   // If the extension uses spanning incognito mode, make sure we're always
674   // using the original profile since that is what the extension process
675   // will use.
676   if (!IncognitoInfo::IsSplitMode(extension))
677     context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
678
679   if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
680     return false;
681
682   pending_lazy_background_page_channels_
683       [GET_CHANNEL_ID(params->receiver_port_id)] =
684           PendingLazyBackgroundPageChannel(context, extension->id());
685   scoped_ptr<OpenChannelParams> scoped_params(params);
686   lazy_background_task_queue_->AddPendingTask(
687       context,
688       extension->id(),
689       base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
690                  weak_factory_.GetWeakPtr(),
691                  base::Passed(&scoped_params),
692                  params->source->GetID()));
693   return true;
694 }
695
696 void MessageService::GotDomainBoundCert(scoped_ptr<OpenChannelParams> params,
697                                         const std::string& tls_channel_id) {
698   params->tls_channel_id.assign(tls_channel_id);
699   int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
700
701   PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
702       pending_tls_channel_id_channels_.find(channel_id);
703   if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
704     NOTREACHED();
705     return;
706   }
707
708   BrowserContext* context = params->source->GetBrowserContext();
709
710   const Extension* target_extension =
711       ExtensionSystem::Get(context)->extension_service()->extensions()->GetByID(
712           params->target_extension_id);
713   if (!target_extension) {
714     pending_tls_channel_id_channels_.erase(channel_id);
715     DispatchOnDisconnect(
716         params->source, params->receiver_port_id,
717         kReceivingEndDoesntExistError);
718     return;
719   }
720   PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
721   if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
722           context, target_extension, params.get())) {
723     // Lazy background queue took ownership. Release ours.
724     ignore_result(params.release());
725     // Messages queued up waiting for the TLS channel ID now need to be queued
726     // up for the lazy background page to load.
727     for (PendingMessagesQueue::iterator it = pending_messages.begin();
728          it != pending_messages.end();
729          it++) {
730       EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
731                                                  it->second);
732     }
733   } else {
734     OpenChannelImpl(params.Pass());
735     // Messages queued up waiting for the TLS channel ID can be posted now.
736     MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
737     if (channel_iter != channels_.end()) {
738       for (PendingMessagesQueue::iterator it = pending_messages.begin();
739            it != pending_messages.end();
740            it++) {
741         DispatchMessage(it->first, channel_iter->second, it->second);
742       }
743     }
744   }
745   pending_tls_channel_id_channels_.erase(channel_id);
746 }
747
748 void MessageService::PendingLazyBackgroundPageOpenChannel(
749     scoped_ptr<OpenChannelParams> params,
750     int source_process_id,
751     ExtensionHost* host) {
752   if (!host)
753     return;  // TODO(mpcomplete): notify source of disconnect?
754
755   // Re-lookup the source process since it may no longer be valid.
756   content::RenderProcessHost* source =
757       content::RenderProcessHost::FromID(source_process_id);
758   if (!source)
759     return;
760
761   params->source = source;
762   params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
763                                                   MSG_ROUTING_CONTROL,
764                                                   params->target_extension_id));
765   OpenChannelImpl(params.Pass());
766 }
767
768 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
769                                           int port_id,
770                                           const std::string& error_message) {
771   ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
772   port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
773 }
774
775 }  // namespace extensions