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