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/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
    776