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